* Copyright (c) 1983, 1988, 1989 The Regents of the University of California.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 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
"@(#) Copyright (c) 1983, 1988, 1989 The Regents of the University of California.\n\
static char sccsid
[] = "@(#)rlogind.c 5.53 (Berkeley) 4/20/91";
* $Source: /mit/kerberos/ucb/mit/rlogind/RCS/rlogind.c,v $
* $Header: rlogind.c,v 5.0 89/06/26 18:31:01 kfall Locked $
#define FD_SETSIZE 16 /* don't need many bits for select */
#include <netinet/in_systm.h>
#define TIOCPKT_WINDOW 0x80
#include <kerberosIV/des.h>
#include <kerberosIV/krb.h>
#define SECURE_MESSAGE "This rlogin session is using DES encryption for all transmissions.\r\n"
u_char auth_buf
[sizeof(AUTH_DAT
)];
u_char tick_buf
[sizeof(KTEXT_ST
)];
int doencrypt
, retval
, use_kerberos
, vacuous
;
char lusername
[NMAX
+1], rusername
[NMAX
+1];
static char term
[64] = "TERM=";
#define ENVSIZE (sizeof("TERM=")-1) /* skip null for concatenation */
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, (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);
setsockopt(0, SOL_SOCKET
, SO_KEEPALIVE
, &on
, sizeof (on
)) < 0)
syslog(LOG_WARNING
, "setsockopt (SO_KEEPALIVE): %m");
if (setsockopt(0, IPPROTO_IP
, IP_TOS
, (char *)&on
, sizeof(int)) < 0)
syslog(LOG_WARNING
, "setsockopt (IP_TOS): %m");
extern char *inet_ntoa();
struct winsize win
= { 0, 0, 0, 0 };
struct sockaddr_in
*fromp
;
int i
, master
, 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((char *)&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
);
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
))) {
fatal(f
, "rlogind: Host address mismatch.", 0);
retval
= do_krb_login(hp
->h_name
, fromp
);
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);
u_char optbuf
[BUFSIZ
/3], *cp
;
int optsize
= sizeof(optbuf
), ipproto
;
if ((ip
= getprotobyname("ip")) != NULL
)
if (getsockopt(0, ipproto
, IP_OPTIONS
, (char *)optbuf
,
&optsize
) == 0 && optsize
!= 0) {
for (cp
= optbuf
; optsize
> 0; cp
++, optsize
--, lp
+= 3)
sprintf(lp
, " %2.2x", *cp
);
"Connection received using IP options (ignored):%s",
if (setsockopt(0, ipproto
, IP_OPTIONS
,
(char *)NULL
, optsize
) != 0) {
syslog(LOG_ERR
, "setsockopt IP_OPTIONS NULL: %m");
if (do_rlogin(hp
->h_name
) == 0 && hostok
)
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);
pid
= forkpty(&master
, line
, NULL
, &win
);
fatal(f
, "Out of ptys", 0);
if (f
> 2) /* f should always be 0, but... */
if (use_kerberos
&& (pwd
->pw_uid
== 0))
syslog(LOG_INFO
|LOG_AUTH
,
"ROOT Kerberos login from %s.%s@%s on %s\n",
kdata
->pname
, kdata
->pinst
, kdata
->prealm
,
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);
* If encrypted, don't turn on NBIO or the des read/write
ioctl(master
, FIONBIO
, &on
);
ioctl(master
, TIOCPKT
, &on
);
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
) {
if (FD_ISSET(f
, &ibits
)) {
fcc
= des_read(f
, fibuf
, sizeof(fibuf
));
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) {
FD_SET(f
, &obits
); /* try write */
if (pkcontrol(pibuf
[0])) {
send(f
, &pibuf
[0], 1, MSG_OOB
);
if ((FD_ISSET(f
, &obits
)) && pcc
> 0) {
cc
= des_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
))
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);
register char *cp
= index(term
+ENVSIZE
, '/');
cfsetspeed(&tt
, atoi(speed
));
tt
.c_iflag
= TTYDEF_IFLAG
;
tt
.c_oflag
= TTYDEF_OFLAG
;
tt
.c_lflag
= TTYDEF_LFLAG
;
tcsetattr(fd
, TCSAFLUSH
, &tt
);
cfsetspeed(&tt
, atoi(speed
));
tcsetattr(fd
, TCSAFLUSH
, &tt
);
* Do the remote kerberos login to the named host with the
* Return 0 on valid authorization
* Return -1 on valid authentication, no authorization
* Return >0 for error conditions
struct sockaddr_in
*dest
;
char instance
[INST_SZ
], version
[VERSION_SIZE
];
long authopts
= 0L; /* !mutual */
struct sockaddr_in faddr
;
kdata
= (AUTH_DAT
*) auth_buf
;
ticket
= (KTEXT
) tick_buf
;
if (getsockname(0, (struct sockaddr
*)&faddr
, &rc
))
authopts
= KOPT_DO_MUTUAL
;
kdata
, "", schedule
, version
);
des_set_key(kdata
->session
, schedule
);
instance
, dest
, (struct sockaddr_in
*) 0,
kdata
, "", (bit_64
*) 0, version
);
getstr(lusername
, sizeof(lusername
), "locuser");
/* get the "cmd" in the rcmd protocol */
getstr(term
+ENVSIZE
, sizeof(term
)-ENVSIZE
, "Terminal type");
pwd
= getpwnam(lusername
);
/* returns nonzero for no access */
if (kuserok(kdata
,lusername
) != 0)
syslog(LOG_ERR
, "usage: rlogind [-aln] [-k | -v]");
syslog(LOG_ERR
, "usage: rlogind [-aln]");
* 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
--) {