* Copyright (c) 1983, 1988, 1989 The Regents of the University of California.
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
"@(#) Copyright (c) 1983, 1988, 1989 The Regents of the University of California.\n\
static char sccsid
[] = "@(#)rlogind.c 5.43 (Berkeley) %G%";
* $Source: /mit/kerberos/ucb/mit/rlogind/RCS/rlogind.c,v $
* $Header: rlogind.c,v 5.0 89/06/26 18:31:01 kfall Locked $
* Automatic login protocol is done here, using login -f upon success,
* unless OLD_LOGIN is defined (then done in login, ala 4.2/4.3BSD).
#define FD_SETSIZE 16 /* don't need many bits for select */
#define TIOCPKT_WINDOW 0x80
char lusername
[NMAX
+1], rusername
[NMAX
+1];
static char term
[64] = "TERM=";
#define ENVSIZE (sizeof("TERM=")-1) /* skip null for concatenation */
struct passwd
*getpwnam(), *pwd
;
extern int opterr
, optind
;
extern int _check_rhosts_file
;
openlog("rlogind", LOG_PID
| LOG_CONS
, LOG_AUTH
);
while ((ch
= getopt(argc
, argv
, ARGSTR
)) != EOF
)
if (use_kerberos
&& vacuous
) {
fatal(STDERR_FILENO
, "only one of -k and -v allowed", 0);
if (getpeername(0, &from
, &fromlen
) < 0) {
syslog(LOG_ERR
, "Couldn't get peer name of remote host: %m");
fatalperror("Can't get peer name of remote host");
setsockopt(0, SOL_SOCKET
, SO_KEEPALIVE
, &on
, sizeof (on
)) < 0)
syslog(LOG_WARNING
, "setsockopt (SO_KEEPALIVE): %m");
extern char *inet_ntoa();
struct winsize win
= { 0, 0, 0, 0 };
struct sockaddr_in
*fromp
;
int i
, p
, t
, pid
, on
= 1;
int authenticated
= 0, hostok
= 0;
register struct hostent
*hp
;
char remotehost
[2 * MAXHOSTNAMELEN
+ 1];
fatal(f
, "Remote host requires Kerberos authentication", 0);
fromp
->sin_port
= ntohs((u_short
)fromp
->sin_port
);
hp
= gethostbyaddr(&fromp
->sin_addr
, sizeof (struct in_addr
),
* Only the name is used below.
hp
->h_name
= inet_ntoa(fromp
->sin_addr
);
else if (check_all
|| local_domain(hp
->h_name
)) {
* If name returned by gethostbyaddr is in our domain,
* attempt to verify that we haven't been fooled by someone
* in a remote net; look up the name and check that this
* address corresponds to the name.
strncpy(remotehost
, hp
->h_name
, sizeof(remotehost
) - 1);
remotehost
[sizeof(remotehost
) - 1] = 0;
hp
= gethostbyname(remotehost
);
#ifdef h_addr /* 4.2 hack */
for (; hp
->h_addr_list
[0]; hp
->h_addr_list
++)
if (!bcmp(hp
->h_addr_list
[0], (caddr_t
)&fromp
->sin_addr
,
sizeof(fromp
->sin_addr
))) {
if (!bcmp(hp
->h_addr
, (caddr_t
)&fromp
->sin_addr
,
sizeof(fromp
->sin_addr
)))
fatal(f
, "krlogind: Host address mismatch.", 0);
retval
= do_krb_login(hp
->h_name
, fromp
, encrypt
);
fatal(f
, krb_err_txt
[retval
], 0);
confirmed
= 1; /* we sent the null! */
if (fromp
->sin_family
!= AF_INET
||
fromp
->sin_port
>= IPPORT_RESERVED
||
fromp
->sin_port
< IPPORT_RESERVED
/2) {
syslog(LOG_NOTICE
, "Connection from %s on illegal port",
inet_ntoa(fromp
->sin_addr
));
fatal(f
, "Permission denied", 0);
if (do_rlogin(hp
->h_name
) == 0 && hostok
)
for (c
= 'p'; c
<= 's'; c
++) {
line
[strlen("/dev/pty")] = c
;
line
[strlen("/dev/ptyp")] = '0';
if (stat(line
, &stb
) < 0)
for (i
= 0; i
< 16; i
++) {
line
[sizeof("/dev/ptyp") - 1] = "0123456789abcdef"[i
];
fatal(f
, "Out of ptys", 0);
(void) ioctl(p
, TIOCSWINSZ
, &win
);
line
[sizeof(_PATH_DEV
) - 1] = 't';
(void)signal(SIGHUP
, SIG_IGN
);
(void)signal(SIGHUP
, SIG_DFL
);
confirmed
= 1; /* we sent the null! */
(void) des_write(f
, SECURE_MESSAGE
, sizeof(SECURE_MESSAGE
));
if (!authenticated
&& !hostok
)
write(f
, "rlogind: Host address mismatch.\r\n",
sizeof("rlogind: Host address mismatch.\r\n") - 1);
fatalperror(f
, "setsid");
if (ioctl(t
, TIOCSCTTY
, 0) < 0)
fatalperror(f
, "ioctl(sctty)");
fatal(f
, "ioctl(sctty)", 1);
execl("/bin/login", "login", "-r", hp
->h_name
, 0);
execl(_PATH_LOGIN
, "login", "-p",
"-h", hp
->h_name
, "-f", lusername
, 0);
execl(_PATH_LOGIN
, "login", "-p",
"-h", hp
->h_name
, lusername
, 0);
fatal(STDERR_FILENO
, _PATH_LOGIN
, 1);
signal(SIGCHLD
, cleanup
);
signal(SIGCHLD
, SIG_IGN
);
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
if (n
< 4+sizeof (w
) || cp
[2] != 's' || cp
[3] != 's')
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
);
* rlogin "protocol" machine.
char pibuf
[1024+1], fibuf
[1024], *pbp
, *fbp
;
register pcc
= 0, fcc
= 0;
* 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 */
syslog(LOG_ERR
, "select mask too small, increase FD_SETSIZE");
fatal(f
, "internal error (select mask too small)", 0);
fd_set ibits
, obits
, ebits
, *omask
;
if ((n
= select(nfd
, &ibits
, omask
, &ebits
, 0)) < 0) {
/* shouldn't happen... */
#define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))
if (FD_ISSET(p
, &ebits
)) {
if (cc
== 1 && pkcontrol(cntl
)) {
send(f
, &cntl
, 1, MSG_OOB
);
if (cntl
& TIOCPKT_FLUSHWRITE
) {
fcc
= read(f
, fibuf
, sizeof(fibuf
));
if (fcc
< 0 && errno
== EWOULDBLOCK
)
for (cp
= fibuf
; cp
< fibuf
+fcc
-1; cp
++)
n
= control(p
, cp
, left
);
FD_SET(p
, &obits
); /* try write */
if (FD_ISSET(p
, &obits
) && fcc
> 0) {
if (FD_ISSET(p
, &ibits
)) {
pcc
= read(p
, pibuf
, sizeof (pibuf
));
if (pcc
< 0 && errno
== EWOULDBLOCK
)
else if (pibuf
[0] == 0) {
obits
|= fmask
; /* try a write */
if (pkcontrol(pibuf
[0])) {
send(f
, &pibuf
[0], 1, MSG_OOB
);
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
))
p
= line
+ sizeof(_PATH_DEV
) - 1;
char buf
[BUFSIZ
], *bp
= buf
;
* Prepend binary one to message if we haven't sent
* the magic null as confirmation.
*bp
++ = '\01'; /* error indicator */
len
= sprintf(bp
, "rlogind: %s: %s.\r\n",
len
= sprintf(bp
, "rlogind: %s.\r\n", msg
);
(void) write(f
, buf
, bp
+ len
- buf
);
getstr(rusername
, sizeof(rusername
), "remuser too long");
getstr(lusername
, sizeof(lusername
), "locuser too long");
getstr(term
+ENVSIZE
, sizeof(term
)-ENVSIZE
, "Terminal type too long");
pwd
= getpwnam(lusername
);
return(ruserok(host
, 0, rusername
, lusername
));
fatal(STDOUT_FILENO
, errmsg
, 0);
"0", "50", "75", "110", "134", "150", "200", "300", "600",
"1200", "1800", "2400", "4800", "9600", "19200", "38400",
#define NSPEEDS (sizeof(speeds) / sizeof(speeds[0]))
register char *cp
= index(term
, '/'), **cpp
;
cfsetspeed(&tt
, atoi(speed
));
tt
.c_iflag
= TTYDEF_IFLAG
;
tt
.c_oflag
= TTYDEF_OFLAG
;
tt
.c_lflag
= TTYDEF_LFLAG
;
tcsetattr(fd
, TCSADFLUSH
, &tt
);
(void)ioctl(fd
, TIOCGETP
, &sgttyb
);
for (cpp
= speeds
; cpp
< &speeds
[NSPEEDS
]; cpp
++)
if (strcmp(*cpp
, speed
) == 0) {
sgttyb
.sg_ispeed
= sgttyb
.sg_ospeed
= cpp
- speeds
;
sgttyb
.sg_flags
= ECHO
|CRMOD
|ANYP
|XTABS
;
(void)ioctl(fd
, TIOCSETP
, &sgttyb
);
* Check whether host h is in our local domain,
* defined as sharing the last two components of the domain part,
* or the entire domain part if the local domain has only one component.
* If either name is unqualified (contains no '.'),
* assume that the host is local, as it will be
char localhost
[MAXHOSTNAMELEN
];
char *p1
, *p2
, *topdomain();
(void) gethostname(localhost
, sizeof(localhost
));
p1
= topdomain(localhost
);
if (p1
== NULL
|| p2
== NULL
|| !strcasecmp(p1
, p2
))
for (p
= h
+ strlen(h
); p
>= h
; p
--) {