Hi
I have a few quesitons regarding a version of rlogind.c that i'm hacking on. I
'm not crazy enough to think that anyone will use it or distribute it, i'm just doing it as a programming exercise. I use a variation of rlogin.c, for the client, from the one in the original w.rich stevens network prog book.
The server program has a function to multiplex between the network and master-side of the pseudo terminal.This is after a function has been called which opens the master and slave of the pseudo terminal and
exec()s /bin/login like so:
Code:
if(excel("/bin/login", "login", "-p", "-h", hp->h_name, "-f", user_name, (char *)0)== -1)
perror("/bin/login error");
Before the
exec() of
/bin/login the slave side is opened after a
fork() and a
setsid() to put what ever is exec()'d after this
fork() in it's own session. Then the slave-side becomes the CTTY of anything executed in this child. Also
dup2 is then called to set the stdin, stout, stderr to the slave's file descriptor(returned from open()ing the slave-side, as explained above). Thus, i thought,
/bin/login would have it's stdin, stout and std err connected to the slave-side of the pseudo term(?). Is this wrong? What would stop this being the case? What would stop the output from
/bin/login from ending up at the master-side of the tty and thus be output on the socket(to be sent to the client)? Or is it most likely to be the multiplexing of socket/master-side I/O that is wrong? Here is the code that does this multiplexing(of socket and master-side I/O....a tiny bit of it is from the BSD version of rlogind.c):
Code:
/*
* Copyright (c) 1983 The Regents of the University of California.
* All rights reserved.
*
* 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.
*/
max_pfd = max(p_ptr.connfd, p_ptr.fdm);
FD_ZERO(&errorset);
FD_SET(p_ptr.fdm, &errorset);
FD_ZERO(&p_error);
FD_SET(p_ptr.fdm, &p_error);
if ((child = fork()) < 0) {
perror("fork error");
} else if (child == 0) { /* child copies stdin to ptym */
for ( ; ; ) {
errset = errorset;
select(maxfd + 1, NULL, NULL, &errset, NULL);
if(FD_ISSET(p_ptr.fdm, &errset)) {
cc = read(p_ptr.fdm, &cntlbyte, 1);
if(cc == 1 && pkcontrol(cntlbyte)){
cntlbyte |= oobdata[0];
send(p_ptr.connfd, &cntlbyte, 1, MSG_OOB);
if(cntlbyte & TIOCPKT_FLUSHWRITE)
memset(buf, 0, sizeof(buf));
}
}
if ((nread = read(p_ptr.connfd, buf, BUFFSIZE)) < 0)
perror("read error from socket");
else if (nread == 0)
break;
for(ptr = buf; ptr < buf+nread-1; ptr++) {
if(ptr[0] == magic[0] &&
ptr[1] == magic[1]) {
left = nread - (ptr - buf);
n = control(p_ptr.fdm, ptr, left);
if(n) {
left -= n;
if(left > 0)
bcopy(ptr+n, ptr, left);
nread -= n;
}
}
}
if (writen(p_ptr.fdm, buf, nread) != nread)
perror("writen error to master pty");
}/*End of for? */
/*
* We always terminate when we encounter an EOF on stdin,
* but we notify the parent only if ignoreeof is 0.
*/
if (p_ptr.ignoreeof == 0)
kill(getppid(), SIGTERM); /* notify parent */
exit(0); /* and terminate; child can't return */
}/*end of child */
/*
* Parent copies ptym to stdout.
*/
if (signal(SIGTERM, sig_term) == SIG_ERR)
perror("signal_intr error for SIGTERM");
for ( ; ; ) {
p_err = p_error;
/*p_wset = p_write;
p_rset = p_read;*/
select(max_pfd + 1, NULL, NULL, &p_err, NULL);
if(FD_ISSET(p_ptr.fdm, &p_err)) {
cc = read(p_ptr.fdm, &cntlbyte, 1);
if(cc == 1 && pkcontrol(cntlbyte)){
cntlbyte |= oobdata[0];
send(p_ptr.fdm, &cntlbyte, 1, MSG_OOB);
if(cntlbyte & TIOCPKT_FLUSHWRITE)
memset(buf, 0, sizeof(buf));
}
}
if ((nread = read(p_ptr.fdm, buffer, BUFFSIZE)) <= 0){
perror("Read error on pty master");
break; /* signal caught, error, or EOF */
/*if(buffer[0] == 0) {*/
}
if(pkcontrol(buffer[0])) {
buffer[0] |= oobdata[0];
send(p_ptr.connfd, &buffer[0], 1, MSG_OOB);
}else {
if (writen(p_ptr.connfd, buffer, nread) != nread)
perror("writen error to stdout");
}/*else*/
} /*Closes for? */
/*
* There are three ways to get here: sig_term() below caught the
* SIGTERM from the child, we read an EOF on the pty master (which
* means we have to signal the child to stop), or an error.
*/
if (sigcaught == 0) /* tell child if it didn't send us the signal */
kill(child, SIGTERM);
/*
* Parent returns to caller.
*/
/* Need to close connection and do any clean up here
*
*/
close(p_ptr.connfd);
}
return(0);
}
I've looked at
/etc/login.access i even removed the user i was trying to log in as from wheel! I was hoping that with the pseudo term and network set up(the network functions are executing without (p)errors) that
/bin/login would just execute the login shell in the same environment( as you can see i used the "-p" flag to /bin/login! Then when
/bin/login exec()'d /usr/local/bin/bash that the code above would pass the output from bash to the slave-side, which would appear at the master-side(since the slave is in raw-mode). As the slave was put in raw-mode anything output to it would appear as output for the socket and visa-versa(Although the master-side in the server isn't set to raw). Is that the right way to do it? When i run the server on FreeBSD no errors are output. When the client is run on os x there is a read error on the client function called
reader()(from the rlogin client in rich stevens' net prog book).
So do i have to edit /etc/ttys and put "secure" for evert ttyXY? I ran
tcpdump and the only packets exchanged were the client sending the user name and the server successfully reading this and sending back an "o.k". What are the "gotchas" for /bin/login and pseudo terms talking to the network? Why might the login fail? I've tried exec()ing /bin/login with and without the "-f" flag. When i did use the "-f" flag i tried logging in as the user who was already logged in and with a user who was not already logged in! I don't know why i can't get this to work(?)
I can post the whole code of the server and/or the client if necessary. But that is kinda crazy(as is wanting to code such an application as rlogind!)
Any help/suggestions would be gratefully received
Thank you very much in advance.