e3be4d7b7e
Some of rcmd related function is need to be updated to support IPv6. Some of them are already updated as standard document. But there is also several de-facto functions and they are not listed in standard documents. They are, iruserok() (used by rlogind, rshd) ruserok() (used by kerberos, etc) KAME package updated those functions in original way. iruserok_af() ruserok_af() But recently there was discussion on IETF IPng mailing list about how to sync those API, and it is decided, -Those function is not standard and not documented. -But let BSDs sync their API as de-facto. And after some discussion, it is announced that -add update to iruserok() as iruserok_sa() -no ruserok() API change(it is only updated internaly) So I sync those API before 4.0 is released. The changes are, -prototype changes -ruserok() internal update (use iruserok_sa() inside) -removal of ruserok_af() -change iruserok_af() as static functioin, and also prefix the name with __. -add iruserok_sa() (Just call __iruserok_af() inside) -adding flag AI_ALL to getipnodebyaddr() called from __icheckhost(). This is necessary to support IPv4 communication via AF_INET6 socket could be correctly authenticated via iruserok_sa() -irusreok_af() call is replaced to iruserok_sa() call in rlogind, and rshd. Approved by: jkh
669 lines
14 KiB
C
669 lines
14 KiB
C
/*-
|
|
* Copyright (c) 1983, 1988, 1989, 1993
|
|
* The Regents of the University of California. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
* must display the following acknowledgement:
|
|
* This product includes software developed by the University of
|
|
* California, Berkeley and its contributors.
|
|
* 4. Neither the name of the University nor the names of its contributors
|
|
* may be used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*/
|
|
|
|
#ifndef lint
|
|
static const char copyright[] =
|
|
"@(#) Copyright (c) 1983, 1988, 1989, 1993\n\
|
|
The Regents of the University of California. All rights reserved.\n";
|
|
#endif /* not lint */
|
|
|
|
#ifndef lint
|
|
#if 0
|
|
static const char sccsid[] = "@(#)rlogind.c 8.1 (Berkeley) 6/4/93";
|
|
#endif
|
|
static const char rcsid[] =
|
|
"$FreeBSD$";
|
|
#endif /* not lint */
|
|
|
|
/*
|
|
* remote login server:
|
|
* \0
|
|
* remuser\0
|
|
* locuser\0
|
|
* terminal_type/speed\0
|
|
* data
|
|
*/
|
|
|
|
#define FD_SETSIZE 16 /* don't need many bits for select */
|
|
#include <sys/types.h>
|
|
#include <sys/param.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/ioctl.h>
|
|
#include <signal.h>
|
|
#include <termios.h>
|
|
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
#include <netinet/in_systm.h>
|
|
#include <netinet/ip.h>
|
|
#include <netinet/tcp.h>
|
|
#include <arpa/inet.h>
|
|
#include <netdb.h>
|
|
|
|
#include <errno.h>
|
|
#include <libutil.h>
|
|
#include <pwd.h>
|
|
#include <syslog.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include "pathnames.h"
|
|
|
|
#ifndef NO_PAM
|
|
#include <security/pam_appl.h>
|
|
#include <security/pam_misc.h>
|
|
#endif
|
|
|
|
#ifndef TIOCPKT_WINDOW
|
|
#define TIOCPKT_WINDOW 0x80
|
|
#endif
|
|
|
|
#define ARGSTR "Dalnx"
|
|
|
|
/* wrapper for KAME-special getnameinfo() */
|
|
#ifndef NI_WITHSCOPEID
|
|
#define NI_WITHSCOPEID 0
|
|
#endif
|
|
|
|
char *env[2];
|
|
#define NMAX 30
|
|
char lusername[NMAX+1], rusername[NMAX+1];
|
|
static char term[64] = "TERM=";
|
|
#define ENVSIZE (sizeof("TERM=")-1) /* skip null for concatenation */
|
|
int keepalive = 1;
|
|
int check_all = 0;
|
|
int no_delay;
|
|
|
|
struct passwd *pwd;
|
|
|
|
union sockunion {
|
|
struct sockinet {
|
|
u_char si_len;
|
|
u_char si_family;
|
|
u_short si_port;
|
|
} su_si;
|
|
struct sockaddr_in su_sin;
|
|
struct sockaddr_in6 su_sin6;
|
|
};
|
|
#define su_len su_si.si_len
|
|
#define su_family su_si.si_family
|
|
#define su_port su_si.si_port
|
|
|
|
void doit __P((int, union sockunion *));
|
|
int control __P((int, char *, int));
|
|
void protocol __P((int, int));
|
|
void cleanup __P((int));
|
|
void fatal __P((int, char *, int));
|
|
int do_rlogin __P((union sockunion *));
|
|
void getstr __P((char *, int, char *));
|
|
void setup_term __P((int));
|
|
int do_krb_login __P((struct sockaddr_in *));
|
|
void usage __P((void));
|
|
|
|
#ifndef NO_PAM
|
|
extern int auth_pam __P((char *));
|
|
#endif
|
|
|
|
int
|
|
main(argc, argv)
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
extern int __check_rhosts_file;
|
|
union sockunion from;
|
|
int ch, fromlen, on;
|
|
|
|
openlog("rlogind", LOG_PID | LOG_CONS, LOG_AUTH);
|
|
|
|
opterr = 0;
|
|
while ((ch = getopt(argc, argv, ARGSTR)) != -1)
|
|
switch (ch) {
|
|
case 'D':
|
|
no_delay = 1;
|
|
break;
|
|
case 'a':
|
|
check_all = 1;
|
|
break;
|
|
case 'l':
|
|
__check_rhosts_file = 0;
|
|
break;
|
|
case 'n':
|
|
keepalive = 0;
|
|
break;
|
|
#ifdef CRYPT
|
|
case 'x':
|
|
doencrypt = 1;
|
|
break;
|
|
#endif
|
|
case '?':
|
|
default:
|
|
usage();
|
|
break;
|
|
}
|
|
argc -= optind;
|
|
argv += optind;
|
|
|
|
fromlen = sizeof (from);
|
|
if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
|
|
syslog(LOG_ERR,"Can't get peer name of remote host: %m");
|
|
fatal(STDERR_FILENO, "Can't get peer name of remote host", 1);
|
|
}
|
|
on = 1;
|
|
if (keepalive &&
|
|
setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0)
|
|
syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
|
|
if (no_delay &&
|
|
setsockopt(0, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) < 0)
|
|
syslog(LOG_WARNING, "setsockopt (TCP_NODELAY): %m");
|
|
if (from.su_family == AF_INET)
|
|
{
|
|
on = IPTOS_LOWDELAY;
|
|
if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
|
|
syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
|
|
}
|
|
|
|
doit(0, &from);
|
|
return 0;
|
|
}
|
|
|
|
int child;
|
|
int netf;
|
|
char line[MAXPATHLEN];
|
|
int confirmed;
|
|
|
|
struct winsize win = { 0, 0, 0, 0 };
|
|
|
|
|
|
void
|
|
doit(f, fromp)
|
|
int f;
|
|
union sockunion *fromp;
|
|
{
|
|
int master, pid, on = 1;
|
|
int authenticated = 0;
|
|
char hostname[2 * MAXHOSTNAMELEN + 1];
|
|
char nameinfo[2 * INET6_ADDRSTRLEN + 1];
|
|
char c;
|
|
|
|
alarm(60);
|
|
read(f, &c, 1);
|
|
|
|
if (c != 0)
|
|
exit(1);
|
|
|
|
alarm(0);
|
|
|
|
realhostname_sa(hostname, sizeof(hostname) - 1,
|
|
(struct sockaddr *)fromp, fromp->su_len);
|
|
/* error check ? */
|
|
fromp->su_port = ntohs((u_short)fromp->su_port);
|
|
hostname[sizeof(hostname) - 1] = '\0';
|
|
|
|
{
|
|
if ((fromp->su_family != AF_INET &&
|
|
#ifdef INET6
|
|
fromp->su_family != AF_INET6
|
|
#endif
|
|
) ||
|
|
fromp->su_port >= IPPORT_RESERVED ||
|
|
fromp->su_port < IPPORT_RESERVED/2) {
|
|
getnameinfo((struct sockaddr *)fromp,
|
|
fromp->su_len,
|
|
nameinfo, sizeof(nameinfo), NULL, 0,
|
|
NI_NUMERICHOST|NI_WITHSCOPEID);
|
|
/* error check ? */
|
|
syslog(LOG_NOTICE, "Connection from %s on illegal port",
|
|
nameinfo);
|
|
fatal(f, "Permission denied", 0);
|
|
}
|
|
#ifdef IP_OPTIONS
|
|
if (fromp->su_family == AF_INET)
|
|
{
|
|
u_char optbuf[BUFSIZ/3];
|
|
int optsize = sizeof(optbuf), ipproto, i;
|
|
struct protoent *ip;
|
|
|
|
if ((ip = getprotobyname("ip")) != NULL)
|
|
ipproto = ip->p_proto;
|
|
else
|
|
ipproto = IPPROTO_IP;
|
|
if (getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf,
|
|
&optsize) == 0 && optsize != 0) {
|
|
for (i = 0; i < optsize; ) {
|
|
u_char c = optbuf[i];
|
|
if (c == IPOPT_LSRR || c == IPOPT_SSRR) {
|
|
syslog(LOG_NOTICE,
|
|
"Connection refused from %s with IP option %s",
|
|
inet_ntoa(fromp->su_sin.sin_addr),
|
|
c == IPOPT_LSRR ? "LSRR" : "SSRR");
|
|
exit(1);
|
|
}
|
|
if (c == IPOPT_EOL)
|
|
break;
|
|
i += (c == IPOPT_NOP) ? 1 : optbuf[i+1];
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
if (do_rlogin(fromp) == 0)
|
|
authenticated++;
|
|
}
|
|
if (confirmed == 0) {
|
|
write(f, "", 1);
|
|
confirmed = 1; /* we sent the null! */
|
|
}
|
|
#ifdef CRYPT
|
|
if (doencrypt)
|
|
(void) des_enc_write(f,
|
|
SECURE_MESSAGE,
|
|
strlen(SECURE_MESSAGE),
|
|
schedule, &kdata->session);
|
|
#endif
|
|
netf = f;
|
|
|
|
pid = forkpty(&master, line, NULL, &win);
|
|
if (pid < 0) {
|
|
if (errno == ENOENT)
|
|
fatal(f, "Out of ptys", 0);
|
|
else
|
|
fatal(f, "Forkpty", 1);
|
|
}
|
|
if (pid == 0) {
|
|
if (f > 2) /* f should always be 0, but... */
|
|
(void) close(f);
|
|
setup_term(0);
|
|
if (*lusername=='-') {
|
|
syslog(LOG_ERR, "tried to pass user \"%s\" to login",
|
|
lusername);
|
|
fatal(STDERR_FILENO, "invalid user", 0);
|
|
}
|
|
if (authenticated) {
|
|
execl(_PATH_LOGIN, "login", "-p",
|
|
"-h", hostname, "-f", lusername, (char *)NULL);
|
|
} else
|
|
execl(_PATH_LOGIN, "login", "-p",
|
|
"-h", hostname, lusername, (char *)NULL);
|
|
fatal(STDERR_FILENO, _PATH_LOGIN, 1);
|
|
/*NOTREACHED*/
|
|
}
|
|
#ifdef CRYPT
|
|
/*
|
|
* If encrypted, don't turn on NBIO or the des read/write
|
|
* routines will croak.
|
|
*/
|
|
|
|
if (!doencrypt)
|
|
#endif
|
|
ioctl(f, FIONBIO, &on);
|
|
ioctl(master, FIONBIO, &on);
|
|
ioctl(master, TIOCPKT, &on);
|
|
signal(SIGCHLD, cleanup);
|
|
protocol(f, master);
|
|
signal(SIGCHLD, SIG_IGN);
|
|
cleanup(0);
|
|
}
|
|
|
|
char magic[2] = { 0377, 0377 };
|
|
char oobdata[] = {TIOCPKT_WINDOW};
|
|
|
|
/*
|
|
* Handle a "control" request (signaled by magic being present)
|
|
* in the data stream. For now, we are only willing to handle
|
|
* window size changes.
|
|
*/
|
|
int
|
|
control(pty, cp, n)
|
|
int pty;
|
|
char *cp;
|
|
int n;
|
|
{
|
|
struct winsize w;
|
|
|
|
if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's')
|
|
return (0);
|
|
oobdata[0] &= ~TIOCPKT_WINDOW; /* we know he heard */
|
|
bcopy(cp+4, (char *)&w, sizeof(w));
|
|
w.ws_row = ntohs(w.ws_row);
|
|
w.ws_col = ntohs(w.ws_col);
|
|
w.ws_xpixel = ntohs(w.ws_xpixel);
|
|
w.ws_ypixel = ntohs(w.ws_ypixel);
|
|
(void)ioctl(pty, TIOCSWINSZ, &w);
|
|
return (4+sizeof (w));
|
|
}
|
|
|
|
/*
|
|
* rlogin "protocol" machine.
|
|
*/
|
|
void
|
|
protocol(f, p)
|
|
register int f, p;
|
|
{
|
|
char pibuf[1024+1], fibuf[1024], *pbp, *fbp;
|
|
int pcc = 0, fcc = 0;
|
|
int cc, nfd, n;
|
|
char cntl;
|
|
|
|
/*
|
|
* Must ignore SIGTTOU, otherwise we'll stop
|
|
* when we try and set slave pty's window shape
|
|
* (our controlling tty is the master pty).
|
|
*/
|
|
(void) signal(SIGTTOU, SIG_IGN);
|
|
send(f, oobdata, 1, MSG_OOB); /* indicate new rlogin */
|
|
if (f > p)
|
|
nfd = f + 1;
|
|
else
|
|
nfd = p + 1;
|
|
if (nfd > FD_SETSIZE) {
|
|
syslog(LOG_ERR, "select mask too small, increase FD_SETSIZE");
|
|
fatal(f, "internal error (select mask too small)", 0);
|
|
}
|
|
for (;;) {
|
|
fd_set ibits, obits, ebits, *omask;
|
|
|
|
FD_ZERO(&ebits);
|
|
FD_ZERO(&ibits);
|
|
FD_ZERO(&obits);
|
|
omask = (fd_set *)NULL;
|
|
if (fcc) {
|
|
FD_SET(p, &obits);
|
|
omask = &obits;
|
|
} else
|
|
FD_SET(f, &ibits);
|
|
if (pcc >= 0) {
|
|
if (pcc) {
|
|
FD_SET(f, &obits);
|
|
omask = &obits;
|
|
} else
|
|
FD_SET(p, &ibits);
|
|
}
|
|
FD_SET(p, &ebits);
|
|
if ((n = select(nfd, &ibits, omask, &ebits, 0)) < 0) {
|
|
if (errno == EINTR)
|
|
continue;
|
|
fatal(f, "select", 1);
|
|
}
|
|
if (n == 0) {
|
|
/* shouldn't happen... */
|
|
sleep(5);
|
|
continue;
|
|
}
|
|
#define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))
|
|
if (FD_ISSET(p, &ebits)) {
|
|
cc = read(p, &cntl, 1);
|
|
if (cc == 1 && pkcontrol(cntl)) {
|
|
cntl |= oobdata[0];
|
|
send(f, &cntl, 1, MSG_OOB);
|
|
if (cntl & TIOCPKT_FLUSHWRITE) {
|
|
pcc = 0;
|
|
FD_CLR(p, &ibits);
|
|
}
|
|
}
|
|
}
|
|
if (FD_ISSET(f, &ibits)) {
|
|
#ifdef CRYPT
|
|
if (doencrypt)
|
|
fcc = des_enc_read(f, fibuf, sizeof(fibuf),
|
|
schedule, &kdata->session);
|
|
else
|
|
#endif
|
|
fcc = read(f, fibuf, sizeof(fibuf));
|
|
if (fcc < 0 && errno == EWOULDBLOCK)
|
|
fcc = 0;
|
|
else {
|
|
register char *cp;
|
|
int left, n;
|
|
|
|
if (fcc <= 0)
|
|
break;
|
|
fbp = fibuf;
|
|
|
|
top:
|
|
for (cp = fibuf; cp < fibuf+fcc-1; cp++)
|
|
if (cp[0] == magic[0] &&
|
|
cp[1] == magic[1]) {
|
|
left = fcc - (cp-fibuf);
|
|
n = control(p, cp, left);
|
|
if (n) {
|
|
left -= n;
|
|
if (left > 0)
|
|
bcopy(cp+n, cp, left);
|
|
fcc -= n;
|
|
goto top; /* n^2 */
|
|
}
|
|
}
|
|
FD_SET(p, &obits); /* try write */
|
|
}
|
|
}
|
|
|
|
if (FD_ISSET(p, &obits) && fcc > 0) {
|
|
cc = write(p, fbp, fcc);
|
|
if (cc > 0) {
|
|
fcc -= cc;
|
|
fbp += cc;
|
|
}
|
|
}
|
|
|
|
if (FD_ISSET(p, &ibits)) {
|
|
pcc = read(p, pibuf, sizeof (pibuf));
|
|
pbp = pibuf;
|
|
if (pcc < 0 && errno == EWOULDBLOCK)
|
|
pcc = 0;
|
|
else if (pcc <= 0)
|
|
break;
|
|
else if (pibuf[0] == 0) {
|
|
pbp++, pcc--;
|
|
#ifdef CRYPT
|
|
if (!doencrypt)
|
|
#endif
|
|
FD_SET(f, &obits); /* try write */
|
|
} else {
|
|
if (pkcontrol(pibuf[0])) {
|
|
pibuf[0] |= oobdata[0];
|
|
send(f, &pibuf[0], 1, MSG_OOB);
|
|
}
|
|
pcc = 0;
|
|
}
|
|
}
|
|
if ((FD_ISSET(f, &obits)) && pcc > 0) {
|
|
#ifdef CRYPT
|
|
if (doencrypt)
|
|
cc = des_enc_write(f, pbp, pcc,
|
|
schedule, &kdata->session);
|
|
else
|
|
#endif
|
|
cc = write(f, pbp, pcc);
|
|
if (cc < 0 && errno == EWOULDBLOCK) {
|
|
/*
|
|
* This happens when we try write after read
|
|
* from p, but some old kernels balk at large
|
|
* writes even when select returns true.
|
|
*/
|
|
if (!FD_ISSET(p, &ibits))
|
|
sleep(5);
|
|
continue;
|
|
}
|
|
if (cc > 0) {
|
|
pcc -= cc;
|
|
pbp += cc;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
cleanup(signo)
|
|
int signo;
|
|
{
|
|
char *p;
|
|
|
|
p = line + sizeof(_PATH_DEV) - 1;
|
|
if (logout(p))
|
|
logwtmp(p, "", "");
|
|
(void)chflags(line, 0);
|
|
(void)chmod(line, 0666);
|
|
(void)chown(line, 0, 0);
|
|
*p = 'p';
|
|
(void)chflags(line, 0);
|
|
(void)chmod(line, 0666);
|
|
(void)chown(line, 0, 0);
|
|
shutdown(netf, 2);
|
|
exit(1);
|
|
}
|
|
|
|
void
|
|
fatal(f, msg, syserr)
|
|
int f;
|
|
char *msg;
|
|
int syserr;
|
|
{
|
|
int len;
|
|
char buf[BUFSIZ], *bp = buf;
|
|
|
|
/*
|
|
* Prepend binary one to message if we haven't sent
|
|
* the magic null as confirmation.
|
|
*/
|
|
if (!confirmed)
|
|
*bp++ = '\01'; /* error indicator */
|
|
if (syserr)
|
|
len = sprintf(bp, "rlogind: %s: %s.\r\n",
|
|
msg, strerror(errno));
|
|
else
|
|
len = sprintf(bp, "rlogind: %s.\r\n", msg);
|
|
(void) write(f, buf, bp + len - buf);
|
|
exit(1);
|
|
}
|
|
|
|
int
|
|
do_rlogin(dest)
|
|
union sockunion *dest;
|
|
{
|
|
int retval;
|
|
int af;
|
|
char *addr;
|
|
|
|
getstr(rusername, sizeof(rusername), "remuser too long");
|
|
getstr(lusername, sizeof(lusername), "locuser too long");
|
|
getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type too long");
|
|
|
|
#ifndef NO_PAM
|
|
retval = auth_pam(lusername);
|
|
|
|
if (retval) {
|
|
if (retval == -1) {
|
|
syslog(LOG_ERR, "PAM authentication failed");
|
|
}
|
|
else {
|
|
syslog(LOG_ERR,
|
|
"User %s failed PAM authentication", lusername);
|
|
exit(1);
|
|
}
|
|
}
|
|
#endif
|
|
pwd = getpwnam(lusername);
|
|
if (pwd == NULL)
|
|
return (-1);
|
|
/* XXX why don't we syslog() failure? */
|
|
|
|
return (iruserok_sa(dest, dest->su_len, pwd->pw_uid == 0, rusername,
|
|
lusername));
|
|
}
|
|
|
|
void
|
|
getstr(buf, cnt, errmsg)
|
|
char *buf;
|
|
int cnt;
|
|
char *errmsg;
|
|
{
|
|
char c;
|
|
|
|
do {
|
|
if (read(0, &c, 1) != 1)
|
|
exit(1);
|
|
if (--cnt < 0)
|
|
fatal(STDOUT_FILENO, errmsg, 0);
|
|
*buf++ = c;
|
|
} while (c != 0);
|
|
}
|
|
|
|
extern char **environ;
|
|
|
|
void
|
|
setup_term(fd)
|
|
int fd;
|
|
{
|
|
register char *cp = index(term+ENVSIZE, '/');
|
|
char *speed;
|
|
struct termios tt;
|
|
|
|
#ifndef notyet
|
|
tcgetattr(fd, &tt);
|
|
if (cp) {
|
|
*cp++ = '\0';
|
|
speed = cp;
|
|
cp = index(speed, '/');
|
|
if (cp)
|
|
*cp++ = '\0';
|
|
cfsetspeed(&tt, atoi(speed));
|
|
}
|
|
|
|
tt.c_iflag = TTYDEF_IFLAG;
|
|
tt.c_oflag = TTYDEF_OFLAG;
|
|
tt.c_lflag = TTYDEF_LFLAG;
|
|
tcsetattr(fd, TCSAFLUSH, &tt);
|
|
#else
|
|
if (cp) {
|
|
*cp++ = '\0';
|
|
speed = cp;
|
|
cp = index(speed, '/');
|
|
if (cp)
|
|
*cp++ = '\0';
|
|
tcgetattr(fd, &tt);
|
|
cfsetspeed(&tt, atoi(speed));
|
|
tcsetattr(fd, TCSAFLUSH, &tt);
|
|
}
|
|
#endif
|
|
|
|
env[0] = term;
|
|
env[1] = 0;
|
|
environ = env;
|
|
}
|
|
|
|
void
|
|
usage()
|
|
{
|
|
syslog(LOG_ERR, "usage: rlogind [-" ARGSTR "]");
|
|
}
|