home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume25 / rlogin-hack < prev    next >
Encoding:
Text File  |  1992-01-11  |  36.7 KB  |  1,654 lines

  1. Newsgroups: comp.sources.unix
  2. From: gritton@ee.byu.edu (James Gritton)
  3. Subject: v25i105: Enhanced BSD Rlogin to support environment passing
  4. Sender: sources-moderator@pa.dec.com
  5. Approved: vixie@pa.dec.com
  6.  
  7. Submitted-By: gritton@ee.byu.edu (James Gritton)
  8. Posting-Number: Volume 25, Issue 105
  9. Archive-Name: rlogin-hack
  10.  
  11. After reading the intro to comp.sources.unix, I hope this counts as one of
  12. those cases where a submittal can be accepted without a man page or makefile.
  13.  
  14. As mentioned in the README, this is not so much source as a bit of code for
  15. hackers to apply. The meat of the submission is the diff files, which are (I
  16. hope) explained in the README adequately for any who would try this out.
  17.  
  18. As I have only pure BSD sources, this has been test only on pure BSD (4.3 on
  19. a microvax), but the gist of the diff should be applicable anywhere.
  20.  
  21. If you think this would fit better in another group, please tell me. I talked
  22. about this idea in comp.unix.wizards, and got a couple of suggestions to post
  23. it here. Just please don't relegate me to an alt group.
  24.  
  25.     gritton@ee.byu.edu (James Gritton)
  26.  
  27. #!/bin/sh
  28. #
  29. # This is a shell archive.  Remove anything before this line,
  30. # then unpack it by saving it in a file and typing "sh file".
  31. #
  32. # Wrapped by Jamie Gritton <gritton@ee.byu.edu> on Tue Dec 24 00:00:23 1991
  33. #
  34. # This archive contains:
  35. #    rlogin    
  36. #
  37.  
  38. LANG=""; export LANG
  39. PATH=/bin:/usr/bin:$PATH; export PATH
  40.  
  41. echo mkdir - rlogin
  42. mkdir rlogin
  43.  
  44. echo x - rlogin/login.c
  45. cat >rlogin/login.c <<'@EOF'
  46. /*
  47.  * Copyright (c) 1980 Regents of the University of California.
  48.  * All rights reserved.  The Berkeley software License Agreement
  49.  * specifies the terms and conditions for redistribution.
  50.  */
  51.  
  52. #ifndef lint
  53. char copyright[] =
  54. "@(#) Copyright (c) 1980 Regents of the University of California.\n\
  55.  All rights reserved.\n";
  56. #endif not lint
  57.  
  58. #ifndef lint
  59. static char sccsid[] = "@(#)login.c    5.15 (Berkeley) 4/12/86";
  60. #endif not lint
  61.  
  62. /*
  63.  * login [ name ]
  64.  * login -r hostname (for rlogind)
  65.  * login -h hostname (for telnetd, etc.)
  66.  */
  67.  
  68. #include <sys/param.h>
  69. #include <sys/stat.h>
  70. #include <sys/time.h>
  71. #include <sys/resource.h>
  72. #include <sys/file.h>
  73.  
  74. #include <sgtty.h>
  75. #include <utmp.h>
  76. #include <signal.h>
  77. #include <pwd.h>
  78. #include <stdio.h>
  79. #include <lastlog.h>
  80. #include <errno.h>
  81. #include <ttyent.h>
  82. #include <syslog.h>
  83. #include <grp.h>
  84.  
  85. #define TTYGRPNAME    "tty"        /* name of group to own ttys */
  86. #define TTYGID(gid)    tty_gid(gid)    /* gid that owns all ttys */
  87.  
  88. #define    SCMPN(a, b)    strncmp(a, b, sizeof(a))
  89. #define    SCPYN(a, b)    strncpy(a, b, sizeof(a))
  90.  
  91. #define NMAX    sizeof(utmp.ut_name)
  92. #define HMAX    sizeof(utmp.ut_host)
  93.  
  94. #define    FALSE    0
  95. #define    TRUE    -1
  96.  
  97. #define QUOTAWARN       "/usr/ucb/quota -q"        /* warn user about quotas */
  98.  
  99. char    nolog[] =    "/etc/nologin";
  100. char    qlog[]  =    ".hushlogin";
  101. char    maildir[30] =    "/usr/spool/mail/";
  102. char    lastlog[] =    "/usr/adm/lastlog";
  103. struct    passwd nouser = {"", "nope", -1, -1, -1, "", "", "", "" };
  104. struct    sgttyb ttyb;
  105. struct    utmp utmp;
  106. char    minusnam[16] = "-";
  107. char    *envinitstr = 0;
  108. char    **envinit = &envinitstr;    /* now set by setenv calls */
  109. int    nextenv = 0;
  110. /*
  111.  * This bounds the time given to login.  We initialize it here
  112.  * so it can be patched on machines where it's too small.
  113.  */
  114. int    timeout = 60;
  115.  
  116. char    term[64];
  117.  
  118. struct    passwd *pwd;
  119. char    *strcat(), *rindex(), *index(), *malloc(), *realloc();
  120. int    timedout();
  121. char    *ttyname();
  122. char    *crypt();
  123. char    *getpass();
  124. char    *stypeof();
  125. extern    char **environ;
  126. extern    int errno;
  127.  
  128. struct    tchars tc = {
  129.     CINTR, CQUIT, CSTART, CSTOP, CEOT, CBRK
  130. };
  131. struct    ltchars ltc = {
  132.     CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE, CLNEXT
  133. };
  134.  
  135. struct winsize win = { 0, 0, 0, 0 };
  136.  
  137. int    rflag;
  138. int    usererr = -1;
  139. char    rusername[NMAX+1], lusername[NMAX+1];
  140. char    rpassword[NMAX+1];
  141. char    name[NMAX+1];
  142. char    *rhost;
  143.  
  144. main(argc, argv)
  145.     char *argv[];
  146. {
  147.     register char *namep;
  148.     int pflag = 0, hflag = 0, t, f, c;
  149.     int invalid, quietlog;
  150.     FILE *nlfd;
  151.     char *ttyn, *tty;
  152.     int ldisc = 0, zero = 0, i;
  153.     char **envnew;
  154.  
  155.     signal(SIGALRM, timedout);
  156.     alarm(timeout);
  157.     signal(SIGQUIT, SIG_IGN);
  158.     signal(SIGINT, SIG_IGN);
  159.     setpriority(PRIO_PROCESS, 0, 0);
  160.     /*
  161.      * -p is used by getty to tell login not to destroy the environment
  162.      * -r is used by rlogind to cause the autologin protocol;
  163.      * -h is used by other servers to pass the name of the
  164.      * remote host to login so that it may be placed in utmp and wtmp
  165.      */
  166.     while (argc > 1) {
  167.         if (strcmp(argv[1], "-r") == 0) {
  168.             if (rflag || hflag) {
  169.                 printf("Only one of -r and -h allowed\n");
  170.                 exit(1);
  171.             }
  172.             rflag = 1;
  173.             usererr = doremotelogin(argv[2]);
  174.             SCPYN(utmp.ut_host, argv[2]);
  175.             argc -= 2;
  176.             argv += 2;
  177.             continue;
  178.         }
  179.         if (strcmp(argv[1], "-h") == 0 && getuid() == 0) {
  180.             if (rflag || hflag) {
  181.                 printf("Only one of -r and -h allowed\n");
  182.                 exit(1);
  183.             }
  184.             hflag = 1;
  185.             SCPYN(utmp.ut_host, argv[2]);
  186.             argc -= 2;
  187.             argv += 2;
  188.             continue;
  189.         }
  190.         if (strcmp(argv[1], "-p") == 0) {
  191.             argc--;
  192.             argv++;
  193.             pflag = 1;
  194.             continue;
  195.         }
  196.         break;
  197.     }
  198.     ioctl(0, TIOCLSET, &zero);
  199.     ioctl(0, TIOCNXCL, 0);
  200.     ioctl(0, FIONBIO, &zero);
  201.     ioctl(0, FIOASYNC, &zero);
  202.     ioctl(0, TIOCGETP, &ttyb);
  203.     /*
  204.      * If talking to an rlogin process,
  205.      * propagate the terminal type and
  206.      * baud rate across the network.
  207.      */
  208.     if (rflag)
  209.         doremoteterm(term, &ttyb);
  210.     ttyb.sg_erase = CERASE;
  211.     ttyb.sg_kill = CKILL;
  212.     ioctl(0, TIOCSLTC, <c);
  213.     ioctl(0, TIOCSETC, &tc);
  214.     ioctl(0, TIOCSETP, &ttyb);
  215.     for (t = getdtablesize(); t > 2; t--)
  216.         close(t);
  217.     ttyn = ttyname(0);
  218.     if (ttyn == (char *)0 || *ttyn == '\0')
  219.         ttyn = "/dev/tty??";
  220.     tty = rindex(ttyn, '/');
  221.     if (tty == NULL)
  222.         tty = ttyn;
  223.     else
  224.         tty++;
  225.     openlog("login", LOG_ODELAY, LOG_AUTH);
  226.     t = 0;
  227.     invalid = FALSE;
  228.     do {
  229.         ldisc = 0;
  230.         ioctl(0, TIOCSETD, &ldisc);
  231.         SCPYN(utmp.ut_name, "");
  232.         /*
  233.          * Name specified, take it.
  234.          */
  235.         if (argc > 1) {
  236.             SCPYN(utmp.ut_name, argv[1]);
  237.             argc = 0;
  238.         }
  239.         /*
  240.          * If remote login take given name,
  241.          * otherwise prompt user for something.
  242.          */
  243.         if (rflag && !invalid)
  244.             SCPYN(utmp.ut_name, lusername);
  245.         else
  246.             getloginname(&utmp);
  247.         invalid = FALSE;
  248.         if (!strcmp(pwd->pw_shell, "/bin/csh")) {
  249.             ldisc = NTTYDISC;
  250.             ioctl(0, TIOCSETD, &ldisc);
  251.         }
  252.         /*
  253.          * If no remote login authentication and
  254.          * a password exists for this user, prompt
  255.          * for one and verify it.
  256.          */
  257.         if (usererr == -1 && *pwd->pw_passwd != '\0') {
  258.             char *pp;
  259.  
  260.             setpriority(PRIO_PROCESS, 0, -4);
  261.             pp = getpass("Password:");
  262.             namep = crypt(pp, pwd->pw_passwd);
  263.             setpriority(PRIO_PROCESS, 0, 0);
  264.             if (strcmp(namep, pwd->pw_passwd))
  265.                 invalid = TRUE;
  266.         }
  267.         /*
  268.          * If user not super-user, check for logins disabled.
  269.          */
  270.         if (pwd->pw_uid != 0 && (nlfd = fopen(nolog, "r")) > 0) {
  271.             while ((c = getc(nlfd)) != EOF)
  272.                 putchar(c);
  273.             fflush(stdout);
  274.             sleep(5);
  275.             exit(0);
  276.         }
  277.         /*
  278.          * If valid so far and root is logging in,
  279.          * see if root logins on this terminal are permitted.
  280.          */
  281.         if (!invalid && pwd->pw_uid == 0 && !rootterm(tty)) {
  282.             if (utmp.ut_host[0])
  283.                 syslog(LOG_CRIT,
  284.                     "ROOT LOGIN REFUSED ON %s FROM %.*s",
  285.                     tty, HMAX, utmp.ut_host);
  286.             else
  287.                 syslog(LOG_CRIT,
  288.                     "ROOT LOGIN REFUSED ON %s", tty);
  289.             invalid = TRUE;
  290.         }
  291.         if (invalid) {
  292.             printf("Login incorrect\n");
  293.             if (++t >= 5) {
  294.                 if (utmp.ut_host[0])
  295.                     syslog(LOG_CRIT,
  296.                         "REPEATED LOGIN FAILURES ON %s FROM %.*s, %.*s",
  297.                         tty, HMAX, utmp.ut_host,
  298.                         NMAX, utmp.ut_name);
  299.                 else
  300.                     syslog(LOG_CRIT,
  301.                         "REPEATED LOGIN FAILURES ON %s, %.*s",
  302.                         tty, NMAX, utmp.ut_name);
  303.                 ioctl(0, TIOCHPCL, (struct sgttyb *) 0);
  304.                 close(0), close(1), close(2);
  305.                 sleep(10);
  306.                 exit(1);
  307.             }
  308.         }
  309.         if (*pwd->pw_shell == '\0')
  310.             pwd->pw_shell = "/bin/sh";
  311.         if (chdir(pwd->pw_dir) < 0 && !invalid ) {
  312.             if (chdir("/") < 0) {
  313.                 printf("No directory!\n");
  314.                 invalid = TRUE;
  315.             } else {
  316.                 printf("No directory! %s\n",
  317.                    "Logging in with home=/");
  318.                 pwd->pw_dir = "/";
  319.             }
  320.         }
  321.         /*
  322.          * Remote login invalid must have been because
  323.          * of a restriction of some sort, no extra chances.
  324.          */
  325.         if (!usererr && invalid)
  326.             exit(1);
  327.     } while (invalid);
  328. /* committed to login turn off timeout */
  329.     alarm(0);
  330.  
  331.     time(&utmp.ut_time);
  332.     t = ttyslot();
  333.     if (t > 0 && (f = open("/etc/utmp", O_WRONLY)) >= 0) {
  334.         lseek(f, (long)(t*sizeof(utmp)), 0);
  335.         SCPYN(utmp.ut_line, tty);
  336.         write(f, (char *)&utmp, sizeof(utmp));
  337.         close(f);
  338.     }
  339.     if ((f = open("/usr/adm/wtmp", O_WRONLY|O_APPEND)) >= 0) {
  340.         write(f, (char *)&utmp, sizeof(utmp));
  341.         close(f);
  342.     }
  343.     quietlog = access(qlog, F_OK) == 0;
  344.     if ((f = open(lastlog, O_RDWR)) >= 0) {
  345.         struct lastlog ll;
  346.  
  347.         lseek(f, (long)pwd->pw_uid * sizeof (struct lastlog), 0);
  348.         if (read(f, (char *) &ll, sizeof ll) == sizeof ll &&
  349.             ll.ll_time != 0 && !quietlog) {
  350.             printf("Last login: %.*s ",
  351.                 24-5, (char *)ctime(&ll.ll_time));
  352.             if (*ll.ll_host != '\0')
  353.                 printf("from %.*s\n",
  354.                     sizeof (ll.ll_host), ll.ll_host);
  355.             else
  356.                 printf("on %.*s\n",
  357.                     sizeof (ll.ll_line), ll.ll_line);
  358.         }
  359.         lseek(f, (long)pwd->pw_uid * sizeof (struct lastlog), 0);
  360.         time(&ll.ll_time);
  361.         SCPYN(ll.ll_line, tty);
  362.         SCPYN(ll.ll_host, utmp.ut_host);
  363.         write(f, (char *) &ll, sizeof ll);
  364.         close(f);
  365.     }
  366.     chown(ttyn, pwd->pw_uid, TTYGID(pwd->pw_gid));
  367.     if (!hflag && !rflag)                    /* XXX */
  368.         ioctl(0, TIOCSWINSZ, &win);
  369.     chmod(ttyn, 0620);
  370.     setgid(pwd->pw_gid);
  371.     strncpy(name, utmp.ut_name, NMAX);
  372.     name[NMAX] = '\0';
  373.     initgroups(name, pwd->pw_gid);
  374.     setuid(pwd->pw_uid);
  375.     /* destroy environment unless user has asked to preserve it */
  376.     if (!pflag)
  377.         environ = envinit;
  378.  
  379.     /* set up environment, this time without destruction */
  380.     /* copy the environment before setenving */
  381.     i = 0;
  382.     while (environ[i] != NULL)
  383.         i++;
  384.     envnew = (char **) malloc(sizeof (char *) * (i + 1));
  385.     for (; i >= 0; i--)
  386.         envnew[i] = environ[i];
  387.     environ = envnew;
  388.  
  389.     setenv("HOME=", pwd->pw_dir, 1);
  390.     setenv("SHELL=", pwd->pw_shell, 1);
  391.     if (term[0] == '\0')
  392.         strncpy(term, stypeof(tty), sizeof(term));
  393.     setenv("TERM=", term, 0);
  394.     setenv("USER=", pwd->pw_name, 1);
  395.     setenv("PATH=", ":/usr/ucb:/bin:/usr/bin", 0);
  396.  
  397.     if ((namep = rindex(pwd->pw_shell, '/')) == NULL)
  398.         namep = pwd->pw_shell;
  399.     else
  400.         namep++;
  401.     strcat(minusnam, namep);
  402.     if (tty[sizeof("tty")-1] == 'd')
  403.         syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
  404.     if (pwd->pw_uid == 0)
  405.         if (utmp.ut_host[0])
  406.             syslog(LOG_NOTICE, "ROOT LOGIN %s FROM %.*s",
  407.                 tty, HMAX, utmp.ut_host);
  408.         else
  409.             syslog(LOG_NOTICE, "ROOT LOGIN %s", tty);
  410.     if (!quietlog) {
  411.         struct stat st;
  412.  
  413.         showmotd();
  414.         strcat(maildir, pwd->pw_name);
  415.         if (stat(maildir, &st) == 0 && st.st_size != 0)
  416.             printf("You have %smail.\n",
  417.                 (st.st_mtime > st.st_atime) ? "new " : "");
  418.         system(QUOTAWARN);
  419.     }
  420.     signal(SIGALRM, SIG_DFL);
  421.     signal(SIGQUIT, SIG_DFL);
  422.     signal(SIGINT, SIG_DFL);
  423.     signal(SIGTSTP, SIG_IGN);
  424.     execlp(pwd->pw_shell, minusnam, 0);
  425.     perror(pwd->pw_shell);
  426.     printf("No shell\n");
  427.     exit(0);
  428. }
  429.  
  430. getloginname(up)
  431.     register struct utmp *up;
  432. {
  433.     register char *namep;
  434.     char c;
  435.  
  436.     while (up->ut_name[0] == '\0') {
  437.         namep = up->ut_name;
  438.         printf("login: ");
  439.         while ((c = getchar()) != '\n') {
  440.             if (c == ' ')
  441.                 c = '_';
  442.             if (c == EOF)
  443.                 exit(0);
  444.             if (namep < up->ut_name+NMAX)
  445.                 *namep++ = c;
  446.         }
  447.     }
  448.     strncpy(lusername, up->ut_name, NMAX);
  449.     lusername[NMAX] = 0;
  450.     if ((pwd = getpwnam(lusername)) == NULL)
  451.         pwd = &nouser;
  452. }
  453.  
  454. timedout()
  455. {
  456.  
  457.     printf("Login timed out after %d seconds\n", timeout);
  458.     exit(0);
  459. }
  460.  
  461. int    stopmotd;
  462. catch()
  463. {
  464.  
  465.     signal(SIGINT, SIG_IGN);
  466.     stopmotd++;
  467. }
  468.  
  469. rootterm(tty)
  470.     char *tty;
  471. {
  472.     register struct ttyent *t;
  473.  
  474.     if ((t = getttynam(tty)) != NULL) {
  475.         if (t->ty_status & TTY_SECURE)
  476.             return (1);
  477.     }
  478.     return (0);
  479. }
  480.  
  481. showmotd()
  482. {
  483.     FILE *mf;
  484.     register c;
  485.  
  486.     signal(SIGINT, catch);
  487.     if ((mf = fopen("/etc/motd", "r")) != NULL) {
  488.         while ((c = getc(mf)) != EOF && stopmotd == 0)
  489.             putchar(c);
  490.         fclose(mf);
  491.     }
  492.     signal(SIGINT, SIG_IGN);
  493. }
  494.  
  495. #undef    UNKNOWN
  496. #define UNKNOWN "su"
  497.  
  498. char *
  499. stypeof(ttyid)
  500.     char *ttyid;
  501. {
  502.     register struct ttyent *t;
  503.  
  504.     if (ttyid == NULL || (t = getttynam(ttyid)) == NULL)
  505.         return (UNKNOWN);
  506.     return (t->ty_type);
  507. }
  508.  
  509. doremotelogin(host)
  510.     char *host;
  511. {
  512.     char    *cp, *flags;
  513.     char    envbuf[256];
  514.  
  515.     getstr(rusername, sizeof (rusername), "remuser");
  516.     getstr(lusername, sizeof (lusername), "locuser");
  517.     getstr(term, sizeof(term), "Terminal type");
  518.     if (getuid()) {
  519.         pwd = &nouser;
  520.         return(-1);
  521.     }
  522.     pwd = getpwnam(lusername);
  523.     if (pwd == NULL) {
  524.         pwd = &nouser;
  525.         return(-1);
  526.     }
  527.     if ((cp = index( term, '/')) && (cp = index( cp + 1, '/'))) {
  528.         *cp++ = 0;
  529.         flags = cp;
  530.         if (cp = index( cp, '/'))
  531.             *cp = 0;
  532.         if (index( flags, 'e')) {
  533.             write( 0, "", 1);
  534.             for (;;) {
  535.                 getstr( envbuf, sizeof (envbuf), "environment");
  536.                 if (envbuf[0]) {
  537.                     if (nextenv)
  538.                         envinit = (char **)realloc(
  539.                             envinit, sizeof( char
  540.                             **) * (nextenv + 2));
  541.                     else
  542.                         envinit = (char **)malloc(
  543.                             sizeof( char **) * 2);
  544.                     envinit[nextenv]
  545.                         = malloc( strlen( envbuf) + 1);
  546.                     strcpy( envinit[nextenv], envbuf);
  547.                     envinit[++nextenv] = 0;
  548.                 } else {
  549.                     envinit[nextenv] = 0;
  550.                     break;
  551.                 }
  552.             }
  553.         }
  554.     }
  555.     return(ruserok(host, (pwd->pw_uid == 0), rusername, lusername));
  556. }
  557.  
  558. getstr(buf, cnt, err)
  559.     char *buf;
  560.     int cnt;
  561.     char *err;
  562. {
  563.     char c;
  564.  
  565.     do {
  566.         if (read(0, &c, 1) != 1)
  567.             exit(1);
  568.         if (--cnt < 0) {
  569.             printf("%s too long\r\n", err);
  570.             exit(1);
  571.         }
  572.         *buf++ = c;
  573.     } while (c != 0);
  574. }
  575.  
  576. char    *speeds[] =
  577.     { "0", "50", "75", "110", "134", "150", "200", "300",
  578.       "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" };
  579. #define    NSPEEDS    (sizeof (speeds) / sizeof (speeds[0]))
  580.  
  581. doremoteterm(term, tp)
  582.     char *term;
  583.     struct sgttyb *tp;
  584. {
  585.     register char *cp = index(term, '/'), **cpp;
  586.     char *speed;
  587.  
  588.     if (cp) {
  589.         *cp++ = '\0';
  590.         speed = cp;
  591.         for (cpp = speeds; cpp < &speeds[NSPEEDS]; cpp++)
  592.             if (strcmp(*cpp, speed) == 0) {
  593.                 tp->sg_ispeed = tp->sg_ospeed = cpp-speeds;
  594.                 break;
  595.             }
  596.     }
  597.     tp->sg_flags = ECHO|CRMOD|ANYP|XTABS;
  598. }
  599.  
  600. /*
  601.  * Set the value of var to be arg in the Unix 4.2 BSD environment env.
  602.  * Var should end with '='.
  603.  * (bindings are of the form "var=value")
  604.  * This procedure assumes the memory for the first level of environ
  605.  * was allocated using malloc.
  606.  */
  607. setenv(var, value, clobber)
  608.     char *var, *value;
  609. {
  610.     extern char **environ;
  611.     int index = 0;
  612.     int varlen = strlen(var);
  613.     int vallen = strlen(value);
  614.  
  615.     for (index = 0; environ[index] != NULL; index++) {
  616.         if (strncmp(environ[index], var, varlen) == 0) {
  617.             /* found it */
  618.             if (!clobber)
  619.                 return;
  620.             environ[index] = malloc(varlen + vallen + 1);
  621.             strcpy(environ[index], var);
  622.             strcat(environ[index], value);
  623.             return;
  624.         }
  625.     }
  626.     environ = (char **) realloc(environ, sizeof (char *) * (index + 2));
  627.     if (environ == NULL) {
  628.         fprintf(stderr, "login: malloc out of memory\n");
  629.         exit(1);
  630.     }
  631.     environ[index] = malloc(varlen + vallen + 1);
  632.     strcpy(environ[index], var);
  633.     strcat(environ[index], value);
  634.     environ[++index] = NULL;
  635. }
  636.  
  637. tty_gid(default_gid)
  638.     int default_gid;
  639. {
  640.     struct group *getgrnam(), *gr;
  641.     int gid = default_gid;
  642.  
  643.     gr = getgrnam(TTYGRPNAME);
  644.     if (gr != (struct group *) 0)
  645.         gid = gr->gr_gid;
  646.  
  647.     endgrent();
  648.  
  649.     return (gid);
  650. }
  651. @EOF
  652.  
  653. chmod 644 rlogin/login.c
  654.  
  655. echo x - rlogin/README
  656. cat >rlogin/README <<'@EOF'
  657. #
  658. #Enhanced BSD Rlogin to support environment passing: For Hackers Only
  659. #
  660.  
  661. This isn't actually a program, but a patch to existing BSD code.
  662. When communicating between an enhanced client and an enhanced server,
  663. the remote session's environment can be set from the rlogin command line.
  664. Don't try to use this unless you know what you're doing.
  665.  
  666. I based this patch on the (somewhat out of date) 1986 BSD code I have
  667. available. It has been tested using this code on a Microvax running
  668. 4.3BSD. The whole source files are included here for convenience, but should
  669. not be expected to work on anything but pure 4.3BSD on a Vax.
  670.  
  671. #
  672. #The Rlogin Protocol, and My Extension:
  673. #
  674.  
  675. If you plan to try this hack, you should be (or become) familiar with
  676. RFC 1258, which describes the Rlogin protocol.
  677.  
  678. In the unaldurated protocol, the client starts out by sending four null-
  679. terminated strings (the first a null string -- just a zero byte):
  680.  
  681. \0
  682. local-username\0
  683. remote-username\0
  684. terminal-type/speed\0
  685.  
  686. The server responds with a single zero byte, and then the protocol goes on to
  687. things that don't concern up here. My change is as follows: the client
  688. sends the four strings, with another field in the fourth.
  689.  
  690. \0
  691. local-username\0
  692. remote-username\0
  693. terminal-type/speed/flags\0
  694.  
  695. The only flag currently defined is 'e', which means the client can send
  696. environment variables. The server responds with not one but two zero bytes,
  697. and the client then sends any environment variables as null-terminated
  698. NAME=VALUE pairs, and then a null string (a zero byte). Then the protocol
  699. resumes as normal.
  700.  
  701. The above was what happens with a modified client and a modified server.
  702. There are two compatablity cases to consider:
  703.  
  704. New client, old server: The client sends the "term/speed/flags" string.
  705. The server ignores the third field, and doesn't send a second zero byte.
  706. When the client gets a nonzero second byte, it skips passing the environment.
  707.  
  708. Old client, new server: The client doesn't pass the "flags" field in the
  709. fourth string, so the server sends only one zero byte, what the client expects.
  710.  
  711. #
  712. #To Use This Hack:
  713. #
  714.  
  715. The rlogin program must be changed on any machine you want this to work from.
  716. If you use 4.3BSD, you may be able to just compile the rlogin.c provided,
  717. but for most systems, you will need existing code for rlogin. The diff
  718. probably won't work automatically for any non-BSD rlogin, but it's short
  719. and you should be able to insert it by hand into the right place. Recompile
  720. rlogin and make sure it's setuid. Be good to yourself and save the old
  721. rlogin program somewhere.
  722.  
  723. The login program must be changed on any machine you want this to work to.
  724. Like rlogin above, you will probably end up hand-splicing the diff file.
  725. This is hackers' work, after all. Note that the rlogind program need not
  726. be changed.
  727.  
  728. #
  729. #Copyright:
  730. #
  731.  
  732. The full source files rlogin.c and login.c are (c) 1983 Regents of the
  733. University of California. My changes are not copyrighted, and come with
  734. no guarantee at all. As I mentioned, I don't expect the actual source
  735. files to be used in most cases, only a deep look at the sources and diffs.
  736. Happy Hacking.
  737.  
  738. James Gritton
  739. gritton@ee.byu.edu
  740. Brigham Young University
  741. Provo UT USA
  742. @EOF
  743.  
  744. chmod 644 rlogin/README
  745.  
  746. echo x - rlogin/rlogin.c
  747. cat >rlogin/rlogin.c <<'@EOF'
  748. /*
  749.  * Copyright (c) 1983 Regents of the University of California.
  750.  * All rights reserved.  The Berkeley software License Agreement
  751.  * specifies the terms and conditions for redistribution.
  752.  */
  753.  
  754. #ifndef lint
  755. char copyright[] =
  756. "@(#) Copyright (c) 1983 Regents of the University of California.\n\
  757.  All rights reserved.\n";
  758. #endif not lint
  759.  
  760. #ifndef lint
  761. static char sccsid[] = "@(#)rlogin.c    5.10 (Berkeley) 3/30/86";
  762. #endif not lint
  763.  
  764. /*
  765.  * rlogin - remote login
  766.  */
  767. #include <sys/param.h>
  768. #include <sys/errno.h>
  769. #include <sys/file.h>
  770. #include <sys/socket.h>
  771. #include <sys/wait.h>
  772.  
  773. #include <netinet/in.h>
  774.  
  775. #include <stdio.h>
  776. #include <sgtty.h>
  777. #include <errno.h>
  778. #include <pwd.h>
  779. #include <signal.h>
  780. #include <setjmp.h>
  781. #include <netdb.h>
  782.  
  783. # ifndef TIOCPKT_WINDOW
  784. # define TIOCPKT_WINDOW 0x80
  785. # endif TIOCPKT_WINDOW
  786.  
  787. char    *index(), *rindex(), *malloc(), *realloc(), *getenv();
  788. struct    passwd *getpwuid();
  789. char    *name;
  790. int    rem;
  791. char    cmdchar = '~';
  792. int    eight;
  793. int    litout;
  794. char    *speeds[] =
  795.     { "0", "50", "75", "110", "134", "150", "200", "300",
  796.       "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" };
  797. char    term[256] = "network";
  798. extern    int errno;
  799. int    lostpeer();
  800. int    dosigwinch = 0;
  801. char    firstchar = 0;
  802. char    **newenvp;
  803. int    nextenv = 0;
  804. #ifndef sigmask
  805. #define sigmask(m)    (1 << ((m)-1))
  806. #endif
  807. #ifdef sun
  808. struct    ttysize winsize;
  809. struct winsize {
  810.     unsigned short ws_row, ws_col;
  811.     unsigned short ws_xpixel, ws_ypixel;
  812. };
  813. #else sun
  814. struct    winsize winsize;
  815. #endif sun
  816. int    sigwinch(), oob();
  817.  
  818. main(argc, argv)
  819.     int argc;
  820.     char **argv;
  821. {
  822.     char *host, *cp;
  823.     struct sgttyb ttyb;
  824.     struct passwd *pwd;
  825.     struct servent *sp;
  826.     int uid, options = 0, oldmask;
  827.     int on = 1;
  828.  
  829.     host = rindex(argv[0], '/');
  830.     if (host)
  831.         host++;
  832.     else
  833.         host = argv[0];
  834.     argv++, --argc;
  835.     if (!strcmp(host, "rlogin"))
  836.         host = *argv++, --argc;
  837. another:
  838.     if (argc > 0 && !strcmp(*argv, "-d")) {
  839.         argv++, argc--;
  840.         options |= SO_DEBUG;
  841.         goto another;
  842.     }
  843.     if (argc > 0 && !strcmp(*argv, "-l")) {
  844.         argv++, argc--;
  845.         if (argc == 0)
  846.             goto usage;
  847.         name = *argv++; argc--;
  848.         goto another;
  849.     }
  850.     if (argc > 0 && !strncmp(*argv, "-e", 2)) {
  851.         cmdchar = argv[0][2];
  852.         argv++, argc--;
  853.         goto another;
  854.     }
  855.     if (argc > 0 && !strcmp(*argv, "-8")) {
  856.         eight = 1;
  857.         argv++, argc--;
  858.         goto another;
  859.     }
  860.     if (argc > 0 && !strcmp(*argv, "-L")) {
  861.         litout = 1;
  862.         argv++, argc--;
  863.         goto another;
  864.     }
  865.     if (argc > 1 && !strcmp(*argv, "-D")) {
  866.         if (nextenv)
  867.             newenvp = (char **)realloc( newenvp, sizeof( char **)
  868.                 * (nextenv + 2));
  869.         else
  870.             newenvp = (char **)malloc( sizeof( char **) * 2);
  871.         newenvp[nextenv] = malloc( strlen( argv[1]) + 1);
  872.         strcpy( newenvp[nextenv], argv[1]);
  873.         newenvp[++nextenv] = 0;
  874.         argv += 2; argc -= 2;
  875.         goto another;
  876.     }
  877.     if (host == 0)
  878.         goto usage;
  879.     if (argc > 0)
  880.         goto usage;
  881.     pwd = getpwuid(getuid());
  882.     if (pwd == 0) {
  883.         fprintf(stderr, "Who are you?\n");
  884.         exit(1);
  885.     }
  886.     sp = getservbyname("login", "tcp");
  887.     if (sp == 0) {
  888.         fprintf(stderr, "rlogin: login/tcp: unknown service\n");
  889.         exit(2);
  890.     }
  891.     cp = getenv("TERM");
  892.     if (cp)
  893.         strcpy(term, cp);
  894.     strcat(term, "/");
  895.     if (ioctl(0, TIOCGETP, &ttyb) == 0)
  896.         strcat(term, speeds[ttyb.sg_ospeed]);
  897.     if (nextenv)
  898.         strcat(term, "/e");
  899. #ifdef sun
  900.     (void) ioctl(0, TIOCGSIZE, &winsize);
  901. #else sun
  902.     (void) ioctl(0, TIOCGWINSZ, &winsize);
  903. #endif sun
  904.     signal(SIGPIPE, lostpeer);
  905.     signal(SIGURG, oob);
  906.     oldmask = sigblock(sigmask(SIGURG));
  907.         rem = rcmd(&host, sp->s_port, pwd->pw_name,
  908.         name ? name : pwd->pw_name, term, 0);
  909.     if (nextenv && read( rem, &firstchar, 1) == 1 && !firstchar) {
  910.         while (nextenv--) {
  911.             write( rem, newenvp[nextenv],
  912.                 strlen( newenvp[nextenv]) + 1);
  913.             free( newenvp[nextenv]);
  914.         }
  915.         write( rem, "", 1);
  916.     }
  917.         if (rem < 0)
  918.                 exit(1);
  919.     if (options & SO_DEBUG &&
  920.         setsockopt(rem, SOL_SOCKET, SO_DEBUG, &on, sizeof (on)) < 0)
  921.         perror("rlogin: setsockopt (SO_DEBUG)");
  922.     uid = getuid();
  923.     if (setuid(uid) < 0) {
  924.         perror("rlogin: setuid");
  925.         exit(1);
  926.     }
  927.     doit(oldmask);
  928.     /*NOTREACHED*/
  929. usage:
  930.     fprintf(stderr,
  931.         "usage: rlogin host [ -ex ] [ -l username ] [ -8 ] [ -L ] [ -D NAME=VALUE ] ...\n");
  932.     exit(1);
  933. }
  934.  
  935. #define CRLF "\r\n"
  936.  
  937. int    child;
  938. int    catchild();
  939. int    writeroob();
  940.  
  941. int    defflags, tabflag;
  942. int    deflflags;
  943. char    deferase, defkill;
  944. struct    tchars deftc;
  945. struct    ltchars defltc;
  946. struct    tchars notc =    { -1, -1, -1, -1, -1, -1 };
  947. struct    ltchars noltc =    { -1, -1, -1, -1, -1, -1 };
  948.  
  949. doit(oldmask)
  950. {
  951.     int exit();
  952.     struct sgttyb sb;
  953.  
  954.     ioctl(0, TIOCGETP, (char *)&sb);
  955.     defflags = sb.sg_flags;
  956.     tabflag = defflags & TBDELAY;
  957.     defflags &= ECHO | CRMOD;
  958.     deferase = sb.sg_erase;
  959.     defkill = sb.sg_kill;
  960.     ioctl(0, TIOCLGET, (char *)&deflflags);
  961.     ioctl(0, TIOCGETC, (char *)&deftc);
  962.     notc.t_startc = deftc.t_startc;
  963.     notc.t_stopc = deftc.t_stopc;
  964.     ioctl(0, TIOCGLTC, (char *)&defltc);
  965.     signal(SIGINT, SIG_IGN);
  966.     signal(SIGHUP, exit);
  967.     signal(SIGQUIT, exit);
  968.     child = fork();
  969.     if (child == -1) {
  970.         perror("rlogin: fork");
  971.         done(1);
  972.     }
  973.     if (child == 0) {
  974.         mode(1);
  975.         sigsetmask(oldmask);
  976.         if (reader() == 0) {
  977.             prf("Connection closed.");
  978.             exit(0);
  979.         }
  980.         sleep(1);
  981.         prf("\007Connection closed.");
  982.         exit(3);
  983.     }
  984.     signal(SIGURG, writeroob);
  985.     sigsetmask(oldmask);
  986.     signal(SIGCHLD, catchild);
  987.     writer();
  988.     prf("Closed connection.");
  989.     done(0);
  990. }
  991.  
  992. done(status)
  993.     int status;
  994. {
  995.  
  996.     mode(0);
  997.     if (child > 0 && kill(child, SIGKILL) >= 0)
  998.         wait((int *)0);
  999.     exit(status);
  1000. }
  1001.  
  1002. /*
  1003.  * This is called when the reader process gets the out-of-band (urgent)
  1004.  * request to turn on the window-changing protocol.
  1005.  */
  1006. writeroob()
  1007. {
  1008.  
  1009.     if (dosigwinch == 0) {
  1010.         sendwindow();
  1011.         signal(SIGWINCH, sigwinch);
  1012.     }
  1013.     dosigwinch = 1;
  1014. }
  1015.  
  1016. catchild()
  1017. {
  1018.     union wait status;
  1019.     int pid;
  1020.  
  1021. again:
  1022.     pid = wait3(&status, WNOHANG|WUNTRACED, 0);
  1023.     if (pid == 0)
  1024.         return;
  1025.     /*
  1026.      * if the child (reader) dies, just quit
  1027.      */
  1028.     if (pid < 0 || pid == child && !WIFSTOPPED(status))
  1029.         done(status.w_termsig | status.w_retcode);
  1030.     goto again;
  1031. }
  1032.  
  1033. /*
  1034.  * writer: write to remote: 0 -> line.
  1035.  * ~.    terminate
  1036.  * ~^Z    suspend rlogin process.
  1037.  * ~^Y  suspend rlogin process, but leave reader alone.
  1038.  */
  1039. writer()
  1040. {
  1041.     char c;
  1042.     register n;
  1043.     register bol = 1;               /* beginning of line */
  1044.     register local = 0;
  1045.  
  1046.     for (;;) {
  1047.         n = read(0, &c, 1);
  1048.         if (n <= 0) {
  1049.             if (n < 0 && errno == EINTR)
  1050.                 continue;
  1051.             break;
  1052.         }
  1053.         /*
  1054.          * If we're at the beginning of the line
  1055.          * and recognize a command character, then
  1056.          * we echo locally.  Otherwise, characters
  1057.          * are echo'd remotely.  If the command
  1058.          * character is doubled, this acts as a 
  1059.          * force and local echo is suppressed.
  1060.          */
  1061.         if (bol) {
  1062.             bol = 0;
  1063.             if (c == cmdchar) {
  1064.                 bol = 0;
  1065.                 local = 1;
  1066.                 continue;
  1067.             }
  1068.         } else if (local) {
  1069.             local = 0;
  1070.             if (c == '.' || c == deftc.t_eofc) {
  1071.                 echo(c);
  1072.                 break;
  1073.             }
  1074.             if (c == defltc.t_suspc || c == defltc.t_dsuspc) {
  1075.                 bol = 1;
  1076.                 echo(c);
  1077.                 stop(c);
  1078.                 continue;
  1079.             }
  1080.             if (c != cmdchar)
  1081.                 write(rem, &cmdchar, 1);
  1082.         }
  1083.         if (write(rem, &c, 1) == 0) {
  1084.             prf("line gone");
  1085.             break;
  1086.         }
  1087.         bol = c == defkill || c == deftc.t_eofc ||
  1088.             c == deftc.t_intrc || c == defltc.t_suspc ||
  1089.             c == '\r' || c == '\n';
  1090.     }
  1091. }
  1092.  
  1093. echo(c)
  1094. register char c;
  1095. {
  1096.     char buf[8];
  1097.     register char *p = buf;
  1098.  
  1099.     c &= 0177;
  1100.     *p++ = cmdchar;
  1101.     if (c < ' ') {
  1102.         *p++ = '^';
  1103.         *p++ = c + '@';
  1104.     } else if (c == 0177) {
  1105.         *p++ = '^';
  1106.         *p++ = '?';
  1107.     } else
  1108.         *p++ = c;
  1109.     *p++ = '\r';
  1110.     *p++ = '\n';
  1111.     write(1, buf, p - buf);
  1112. }
  1113.  
  1114. stop(cmdc)
  1115.     char cmdc;
  1116. {
  1117.     mode(0);
  1118.     signal(SIGCHLD, SIG_IGN);
  1119.     kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP);
  1120.     signal(SIGCHLD, catchild);
  1121.     mode(1);
  1122.     sigwinch();            /* check for size changes */
  1123. }
  1124.  
  1125. #ifdef sun
  1126. sigwinch()
  1127. {
  1128.     struct ttysize ws;
  1129.  
  1130.     if (dosigwinch && ioctl(0, TIOCGSIZE, &ws) == 0 &&
  1131.         bcmp(&ws, &winsize, sizeof (ws))) {
  1132.         winsize = ws;
  1133.         sendwindow();
  1134.     }
  1135. }
  1136.  
  1137. #else sun
  1138. sigwinch()
  1139. {
  1140.     struct winsize ws;
  1141.  
  1142.     if (dosigwinch && ioctl(0, TIOCGWINSZ, &ws) == 0 &&
  1143.         bcmp(&ws, &winsize, sizeof (ws))) {
  1144.         winsize = ws;
  1145.         sendwindow();
  1146.     }
  1147. }
  1148. #endif
  1149.  
  1150. /*
  1151.  * Send the window size to the server via the magic escape
  1152.  */
  1153. sendwindow()
  1154. {
  1155.     char obuf[4 + sizeof (struct winsize)];
  1156.     struct winsize *wp = (struct winsize *)(obuf+4);
  1157.  
  1158.     obuf[0] = 0377;
  1159.     obuf[1] = 0377;
  1160.     obuf[2] = 's';
  1161.     obuf[3] = 's';
  1162. #ifdef sun
  1163.     wp->ws_row = htons(winsize.ts_lines);
  1164.     wp->ws_col = htons(winsize.ts_cols);
  1165.     wp->ws_xpixel = 0;
  1166.     wp->ws_ypixel = 0;
  1167. #else sun
  1168.     wp->ws_row = htons(winsize.ws_row);
  1169.     wp->ws_col = htons(winsize.ws_col);
  1170.     wp->ws_xpixel = htons(winsize.ws_xpixel);
  1171.     wp->ws_ypixel = htons(winsize.ws_ypixel);
  1172. #endif sun
  1173.     (void) write(rem, obuf, sizeof(obuf));
  1174. }
  1175.  
  1176. /*
  1177.  * reader: read from remote: line -> 1
  1178.  */
  1179. #define    READING    1
  1180. #define    WRITING    2
  1181.  
  1182. char    rcvbuf[8 * 1024];
  1183. int    rcvcnt;
  1184. int    rcvstate;
  1185. int    ppid;
  1186. jmp_buf    rcvtop;
  1187.  
  1188. oob()
  1189. {
  1190.     int out = FWRITE, atmark, n;
  1191.     int rcvd = 0;
  1192.     char waste[BUFSIZ], mark;
  1193.     struct sgttyb sb;
  1194.  
  1195.     while (recv(rem, &mark, 1, MSG_OOB) < 0)
  1196.         switch (errno) {
  1197.         
  1198.         case EWOULDBLOCK:
  1199.             /*
  1200.              * Urgent data not here yet.
  1201.              * It may not be possible to send it yet
  1202.              * if we are blocked for output
  1203.              * and our input buffer is full.
  1204.              */
  1205.             if (rcvcnt < sizeof(rcvbuf)) {
  1206.                 n = read(rem, rcvbuf + rcvcnt,
  1207.                     sizeof(rcvbuf) - rcvcnt);
  1208.                 if (n <= 0)
  1209.                     return;
  1210.                 rcvd += n;
  1211.             } else {
  1212.                 n = read(rem, waste, sizeof(waste));
  1213.                 if (n <= 0)
  1214.                     return;
  1215.             }
  1216.             continue;
  1217.                 
  1218.         default:
  1219.             return;
  1220.     }
  1221.     if (mark & TIOCPKT_WINDOW) {
  1222.         /*
  1223.          * Let server know about window size changes
  1224.          */
  1225.         kill(ppid, SIGURG);
  1226.     }
  1227.     if (!eight && (mark & TIOCPKT_NOSTOP)) {
  1228.         ioctl(0, TIOCGETP, (char *)&sb);
  1229.         sb.sg_flags &= ~CBREAK;
  1230.         sb.sg_flags |= RAW;
  1231.         ioctl(0, TIOCSETN, (char *)&sb);
  1232.         notc.t_stopc = -1;
  1233.         notc.t_startc = -1;
  1234.         ioctl(0, TIOCSETC, (char *)¬c);
  1235.     }
  1236.     if (!eight && (mark & TIOCPKT_DOSTOP)) {
  1237.         ioctl(0, TIOCGETP, (char *)&sb);
  1238.         sb.sg_flags &= ~RAW;
  1239.         sb.sg_flags |= CBREAK;
  1240.         ioctl(0, TIOCSETN, (char *)&sb);
  1241.         notc.t_stopc = deftc.t_stopc;
  1242.         notc.t_startc = deftc.t_startc;
  1243.         ioctl(0, TIOCSETC, (char *)¬c);
  1244.     }
  1245.     if (mark & TIOCPKT_FLUSHWRITE) {
  1246.         ioctl(1, TIOCFLUSH, (char *)&out);
  1247.         for (;;) {
  1248.             if (ioctl(rem, SIOCATMARK, &atmark) < 0) {
  1249.                 perror("ioctl");
  1250.                 break;
  1251.             }
  1252.             if (atmark)
  1253.                 break;
  1254.             n = read(rem, waste, sizeof (waste));
  1255.             if (n <= 0)
  1256.                 break;
  1257.         }
  1258.         /*
  1259.          * Don't want any pending data to be output,
  1260.          * so clear the recv buffer.
  1261.          * If we were hanging on a write when interrupted,
  1262.          * don't want it to restart.  If we were reading,
  1263.          * restart anyway.
  1264.          */
  1265.         rcvcnt = 0;
  1266.         longjmp(rcvtop, 1);
  1267.     }
  1268.     /*
  1269.      * If we filled the receive buffer while a read was pending,
  1270.      * longjmp to the top to restart appropriately.  Don't abort
  1271.      * a pending write, however, or we won't know how much was written.
  1272.      */
  1273.     if (rcvd && rcvstate == READING)
  1274.         longjmp(rcvtop, 1);
  1275. }
  1276.  
  1277. /*
  1278.  * reader: read from remote: line -> 1
  1279.  */
  1280. reader()
  1281. {
  1282. #if !defined(BSD) || BSD < 43
  1283.     int pid = -getpid();
  1284. #else
  1285.     int pid = getpid();
  1286. #endif
  1287.     int n, remaining;
  1288.     char *bufp = rcvbuf;
  1289.  
  1290.     signal(SIGTTOU, SIG_IGN);
  1291.     fcntl(rem, F_SETOWN, pid);
  1292.     ppid = getppid();
  1293.     (void) setjmp(rcvtop);
  1294.     for (;;) {
  1295.         while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) {
  1296.             rcvstate = WRITING;
  1297.             n = write(1, bufp, remaining);
  1298.             if (n < 0) {
  1299.                 if (errno != EINTR)
  1300.                     return (-1);
  1301.                 continue;
  1302.             }
  1303.             bufp += n;
  1304.         }
  1305.         bufp = rcvbuf;
  1306.         rcvcnt = 0;
  1307.         rcvstate = READING;
  1308.         if (firstchar) {
  1309.             rcvcnt = 1;
  1310.             *rcvbuf = firstchar;
  1311.             firstchar = 0;
  1312.         } else {
  1313.             rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf));
  1314.             if (rcvcnt == 0)
  1315.                 return (0);
  1316.             if (rcvcnt < 0) {
  1317.                 if (errno == EINTR)
  1318.                     continue;
  1319.                 perror("read");
  1320.                 return (-1);
  1321.             }
  1322.         }
  1323.     }
  1324. }
  1325.  
  1326. mode(f)
  1327. {
  1328.     struct tchars *tc;
  1329.     struct ltchars *ltc;
  1330.     struct sgttyb sb;
  1331.     int    lflags;
  1332.  
  1333.     ioctl(0, TIOCGETP, (char *)&sb);
  1334.     ioctl(0, TIOCLGET, (char *)&lflags);
  1335.     switch (f) {
  1336.  
  1337.     case 0:
  1338.         sb.sg_flags &= ~(CBREAK|RAW|TBDELAY);
  1339.         sb.sg_flags |= defflags|tabflag;
  1340.         tc = &deftc;
  1341.         ltc = &defltc;
  1342.         sb.sg_kill = defkill;
  1343.         sb.sg_erase = deferase;
  1344.         lflags = deflflags;
  1345.         break;
  1346.  
  1347.     case 1:
  1348.         sb.sg_flags |= (eight ? RAW : CBREAK);
  1349.         sb.sg_flags &= ~defflags;
  1350.         /* preserve tab delays, but turn off XTABS */
  1351.         if ((sb.sg_flags & TBDELAY) == XTABS)
  1352.             sb.sg_flags &= ~TBDELAY;
  1353.         tc = ¬c;
  1354.         ltc = &noltc;
  1355.         sb.sg_kill = sb.sg_erase = -1;
  1356.         if (litout)
  1357.             lflags |= LLITOUT;
  1358.         break;
  1359.  
  1360.     default:
  1361.         return;
  1362.     }
  1363.     ioctl(0, TIOCSLTC, (char *)ltc);
  1364.     ioctl(0, TIOCSETC, (char *)tc);
  1365.     ioctl(0, TIOCSETN, (char *)&sb);
  1366.     ioctl(0, TIOCLSET, (char *)&lflags);
  1367. }
  1368.  
  1369. /*VARARGS*/
  1370. prf(f, a1, a2, a3, a4, a5)
  1371.     char *f;
  1372. {
  1373.     fprintf(stderr, f, a1, a2, a3, a4, a5);
  1374.     fprintf(stderr, CRLF);
  1375. }
  1376.  
  1377. lostpeer()
  1378. {
  1379.     signal(SIGPIPE, SIG_IGN);
  1380.     prf("\007Connection closed.");
  1381.     done(1);
  1382. }
  1383.  
  1384. @EOF
  1385.  
  1386. chmod 644 rlogin/rlogin.c
  1387.  
  1388. echo x - rlogin/login.diff
  1389. cat >rlogin/login.diff <<'@EOF'
  1390. *** login.c.orig    Mon Dec 23 22:48:56 1991
  1391. --- login.c    Mon Dec 23 22:53:17 1991
  1392. ***************
  1393. *** 59,65 ****
  1394.   struct    sgttyb ttyb;
  1395.   struct    utmp utmp;
  1396.   char    minusnam[16] = "-";
  1397. ! char    *envinit[] = { 0 };        /* now set by setenv calls */
  1398.   /*
  1399.    * This bounds the time given to login.  We initialize it here
  1400.    * so it can be patched on machines where it's too small.
  1401. --- 59,67 ----
  1402.   struct    sgttyb ttyb;
  1403.   struct    utmp utmp;
  1404.   char    minusnam[16] = "-";
  1405. ! char    *envinitstr = 0;
  1406. ! char    **envinit = &envinitstr;    /* now set by setenv calls */
  1407. ! int    nextenv = 0;
  1408.   /*
  1409.    * This bounds the time given to login.  We initialize it here
  1410.    * so it can be patched on machines where it's too small.
  1411. ***************
  1412. *** 462,467 ****
  1413. --- 464,472 ----
  1414.   doremotelogin(host)
  1415.       char *host;
  1416.   {
  1417. +     char    *cp, *flags;
  1418. +     char    envbuf[256];
  1419.       getstr(rusername, sizeof (rusername), "remuser");
  1420.       getstr(lusername, sizeof (lusername), "locuser");
  1421.       getstr(term, sizeof(term), "Terminal type");
  1422. ***************
  1423. *** 474,479 ****
  1424. --- 479,512 ----
  1425.           pwd = &nouser;
  1426.           return(-1);
  1427.       }
  1428. +     if ((cp = index( term, '/')) && (cp = index( cp + 1, '/'))) {
  1429. +         *cp++ = 0;
  1430. +         flags = cp;
  1431. +         if (cp = index( cp, '/'))
  1432. +             *cp = 0;
  1433. +         if (index( flags, 'e')) {
  1434. +             write( 0, "", 1);
  1435. +             for (;;) {
  1436. +                 getstr( envbuf, sizeof (envbuf), "environment");
  1437. +                 if (envbuf[0]) {
  1438. +                     if (nextenv)
  1439. +                         envinit = (char **)realloc(
  1440. +                             envinit, sizeof( char
  1441. +                             **) * (nextenv + 2));
  1442. +                     else
  1443. +                         envinit = (char **)malloc(
  1444. +                             sizeof( char **) * 2);
  1445. +                     envinit[nextenv]
  1446. +                         = malloc( strlen( envbuf) + 1);
  1447. +                     strcpy( envinit[nextenv], envbuf);
  1448. +                     envinit[++nextenv] = 0;
  1449. +                 } else {
  1450. +                     envinit[nextenv] = 0;
  1451. +                     break;
  1452. +                 }
  1453. +             }
  1454. +         }
  1455. +     }
  1456.       return(ruserok(host, (pwd->pw_uid == 0), rusername, lusername));
  1457.   }
  1458.   
  1459. ***************
  1460. *** 510,518 ****
  1461.       if (cp) {
  1462.           *cp++ = '\0';
  1463.           speed = cp;
  1464. -         cp = index(speed, '/');
  1465. -         if (cp)
  1466. -             *cp++ = '\0';
  1467.           for (cpp = speeds; cpp < &speeds[NSPEEDS]; cpp++)
  1468.               if (strcmp(*cpp, speed) == 0) {
  1469.                   tp->sg_ispeed = tp->sg_ospeed = cpp-speeds;
  1470. --- 543,548 ----
  1471. @EOF
  1472.  
  1473. chmod 644 rlogin/login.diff
  1474.  
  1475. echo x - rlogin/rlogin.diff
  1476. cat >rlogin/rlogin.diff <<'@EOF'
  1477. *** rlogin.c.orig    Mon Dec 23 22:49:12 1991
  1478. --- rlogin.c    Mon Dec 23 23:06:36 1991
  1479. ***************
  1480. *** 37,43 ****
  1481.   # define TIOCPKT_WINDOW 0x80
  1482.   # endif TIOCPKT_WINDOW
  1483.   
  1484. ! char    *index(), *rindex(), *malloc(), *getenv();
  1485.   struct    passwd *getpwuid();
  1486.   char    *name;
  1487.   int    rem;
  1488. --- 37,43 ----
  1489.   # define TIOCPKT_WINDOW 0x80
  1490.   # endif TIOCPKT_WINDOW
  1491.   
  1492. ! char    *index(), *rindex(), *malloc(), *realloc(), *getenv();
  1493.   struct    passwd *getpwuid();
  1494.   char    *name;
  1495.   int    rem;
  1496. ***************
  1497. *** 51,56 ****
  1498. --- 51,59 ----
  1499.   extern    int errno;
  1500.   int    lostpeer();
  1501.   int    dosigwinch = 0;
  1502. + char    firstchar = 0;
  1503. + char    **newenvp;
  1504. + int    nextenv = 0;
  1505.   #ifndef sigmask
  1506.   #define sigmask(m)    (1 << ((m)-1))
  1507.   #endif
  1508. ***************
  1509. *** 112,117 ****
  1510. --- 115,132 ----
  1511.           argv++, argc--;
  1512.           goto another;
  1513.       }
  1514. +     if (argc > 1 && !strcmp(*argv, "-D")) {
  1515. +         if (nextenv)
  1516. +             newenvp = (char **)realloc( newenvp, sizeof( char **)
  1517. +                 * (nextenv + 2));
  1518. +         else
  1519. +             newenvp = (char **)malloc( sizeof( char **) * 2);
  1520. +         newenvp[nextenv] = malloc( strlen( argv[1]) + 1);
  1521. +         strcpy( newenvp[nextenv], argv[1]);
  1522. +         newenvp[++nextenv] = 0;
  1523. +         argv += 2; argc -= 2;
  1524. +         goto another;
  1525. +     }
  1526.       if (host == 0)
  1527.           goto usage;
  1528.       if (argc > 0)
  1529. ***************
  1530. *** 129,138 ****
  1531.       cp = getenv("TERM");
  1532.       if (cp)
  1533.           strcpy(term, cp);
  1534. !     if (ioctl(0, TIOCGETP, &ttyb) == 0) {
  1535. !         strcat(term, "/");
  1536.           strcat(term, speeds[ttyb.sg_ospeed]);
  1537. !     }
  1538.   #ifdef sun
  1539.       (void) ioctl(0, TIOCGSIZE, &winsize);
  1540.   #else sun
  1541. --- 144,154 ----
  1542.       cp = getenv("TERM");
  1543.       if (cp)
  1544.           strcpy(term, cp);
  1545. !     strcat(term, "/");
  1546. !     if (ioctl(0, TIOCGETP, &ttyb) == 0)
  1547.           strcat(term, speeds[ttyb.sg_ospeed]);
  1548. !     if (nextenv)
  1549. !         strcat(term, "/e");
  1550.   #ifdef sun
  1551.       (void) ioctl(0, TIOCGSIZE, &winsize);
  1552.   #else sun
  1553. ***************
  1554. *** 143,148 ****
  1555. --- 159,172 ----
  1556.       oldmask = sigblock(sigmask(SIGURG));
  1557.           rem = rcmd(&host, sp->s_port, pwd->pw_name,
  1558.           name ? name : pwd->pw_name, term, 0);
  1559. +     if (nextenv && read( rem, &firstchar, 1) == 1 && !firstchar) {
  1560. +         while (nextenv--) {
  1561. +             write( rem, newenvp[nextenv],
  1562. +                 strlen( newenvp[nextenv]) + 1);
  1563. +             free( newenvp[nextenv]);
  1564. +         }
  1565. +         write( rem, "", 1);
  1566. +     }
  1567.           if (rem < 0)
  1568.                   exit(1);
  1569.       if (options & SO_DEBUG &&
  1570. ***************
  1571. *** 157,163 ****
  1572.       /*NOTREACHED*/
  1573.   usage:
  1574.       fprintf(stderr,
  1575. !         "usage: rlogin host [ -ex ] [ -l username ] [ -8 ] [ -L ]\n");
  1576.       exit(1);
  1577.   }
  1578.   
  1579. --- 181,187 ----
  1580.       /*NOTREACHED*/
  1581.   usage:
  1582.       fprintf(stderr,
  1583. !         "usage: rlogin host [ -ex ] [ -l username ] [ -8 ] [ -L ] [ -D NAME=VALUE ] ...\n");
  1584.       exit(1);
  1585.   }
  1586.   
  1587. ***************
  1588. *** 534,547 ****
  1589.           bufp = rcvbuf;
  1590.           rcvcnt = 0;
  1591.           rcvstate = READING;
  1592. !         rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf));
  1593. !         if (rcvcnt == 0)
  1594. !             return (0);
  1595. !         if (rcvcnt < 0) {
  1596. !             if (errno == EINTR)
  1597. !                 continue;
  1598. !             perror("read");
  1599. !             return (-1);
  1600.           }
  1601.       }
  1602.   }
  1603. --- 558,577 ----
  1604.           bufp = rcvbuf;
  1605.           rcvcnt = 0;
  1606.           rcvstate = READING;
  1607. !         if (firstchar) {
  1608. !             rcvcnt = 1;
  1609. !             *rcvbuf = firstchar;
  1610. !             firstchar = 0;
  1611. !         } else {
  1612. !             rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf));
  1613. !             if (rcvcnt == 0)
  1614. !                 return (0);
  1615. !             if (rcvcnt < 0) {
  1616. !                 if (errno == EINTR)
  1617. !                     continue;
  1618. !                 perror("read");
  1619. !                 return (-1);
  1620. !             }
  1621.           }
  1622.       }
  1623.   }
  1624. @EOF
  1625.  
  1626. chmod 644 rlogin/rlogin.diff
  1627.  
  1628. echo x - rlogin/README.submit
  1629. cat >rlogin/README.submit <<'@EOF'
  1630. After reading the intro to comp.sources.unix, I hope this counts as one of
  1631. those cases where a submittal can be accepted without a man page or makefile.
  1632.  
  1633. As mentioned in the README, this is not so much source as a bit of code for
  1634. hackers to apply. The meat of the submission is the diff files, which are
  1635. (I hope) explained in the README adequately for any who would try this out.
  1636.  
  1637. As I have only pure BSD sources, this has been test only on pure BSD (4.3
  1638. on a microvax), but the gist of the diff should be applicable anywhere.
  1639.  
  1640. If you think this would fit better in another group, please tell me. I talked
  1641. about this idea in comp.unix.wizards, and got a couple of suggestions to post
  1642. it here. Just please don't relegate me to an alt group.
  1643.  
  1644. James Gritton
  1645. gritton@ee.byu.edu
  1646. @EOF
  1647.  
  1648. chmod 644 rlogin/README.submit
  1649.  
  1650. chmod 755 rlogin
  1651.  
  1652. exit 0
  1653.