LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   *BSD (http://www.linuxquestions.org/questions/%2Absd-17/)
-   -   Need help with C code(BSD-Based rlogind.c) (http://www.linuxquestions.org/questions/%2Absd-17/need-help-with-c-code-bsd-based-rlogind-c-4175465118/)

methodtwo 06-07-2013 09:25 AM

Need help with C code(BSD-Based rlogind.c)
 
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.

methodtwo 06-07-2013 09:27 AM

Should this post be moved to the programming section? I posted it here because while it is UNIX programming it only runs on FreeBSD and OS X at the moment!
Also the firewall is off on the server when i test the code. The client doesn't use rcmd to send the login credentials. It just write()s the username to the socket. The username is then used when /bin/login is exec()'d(as show above)
cheers

methodtwo 07-04-2013 01:42 AM

I found a solution but since no one in is interested( quite rightly so probably!) then i'll just say that it was solved.

kooru 07-13-2013 04:18 AM

Hi methodtwo ;)
Maybe now nobody have interest for your problem, but in the future someone could need about your solutions.

So if you want/can, please post the solutions.

methodtwo 07-18-2013 03:34 PM

Hi
ERm o.k then. The loop to multiplex the i/o from/to the socket/terminal was the one below. It was just an experiment to see if i could implement something that was as nice as the select(2) loop in the BSD version. The answer to that was no as it turned out. However it works! The other bit of the solution was calling the function that this loop is a part of after fork()ing the child to exec() /bin/login(rather than returning from the parent of this exec("/bin/login", etc, etc) child. Thus the child didn't die and so the remote shell stayed up. Sorry that's a really bad explanation but no one cares(quite rightly so!).
Code:

rcvstate = READING;

    if(child_pid == 0){
      for(;;){
        if(rcvstate == READING)
                      if((pcc = read(fdm, pibuf, sizeof(pibuf))) < 0)
                  continue;
             
          if(pcc > 1){
              rcvstate = WRITING;
              pbp = pibuf;
          }
       
        if(pcc == 0)
              break;
              else if (pcc == 1 && pkcontrol(pibuf[0])) {
                pibuf[0] |= oobdata[0];
                (void)send(connfd, &pibuf[0], 1, MSG_OOB);
                if (pibuf[0] & TIOCPKT_FLUSHWRITE)
                        pcc = 0;
                }
        else if (pcc > 1 && pibuf[0] == 0
                && rcvstate == WRITING){
              pbp++;

                while((rem = pcc - (pbp - pibuf)) > 0){
                if((n = write(connfd, pbp, rem)) < 0){
                    sleep(1);
                    continue;
                }
                if(n == 0)
                    break;
                pbp += n;
        }
        if(rem == 0)
          rcvstate = READING;
        if(n ==0)
          break;
     
                 
      } else {
              if (pkcontrol(pibuf[0])) {
                pibuf[0] |= oobdata[0];
                (void)send(connfd, &pibuf[0], 1 , MSG_OOB);
        }
        pcc = 0;
    }
   
  } /* End of for.... */
 if(ignoreeof == 0)
    kill(getppid(), SIGTERM);
 exit(0);
}/* End of child */

/* Parent........*/
 
  if(signal(SIGTERM, sig_term) == SIG_ERR)
        perror("signal handler for protocol parent!");
  rcvstate = READING;
        for(;;){

          if(rcvstate == READING){
            if((fcc = read(connfd, fibuf, sizeof(fibuf))) < 0)
                  continue;
          if(fcc == 0)
            break;
          if(fcc > 0){
            cc = fcc;
            rcvstate = WRITING;
          }
      }
          if(fcc > 0 && rcvstate == WRITING){
            fbp = fibuf;
          if(fibuf[0] == magic[0] &&
                  fibuf[1] == magic[1]) {
        top:
            for(cp = fibuf; cp < fibuf+fcc-1; cp++)
              if(cp[0] == magic[0] &&
                  cp[1] == magic[1]) {
                    remaining = fcc - (cp-fibuf);
                    n = control(fdm, cp, remaining);
                    if(n){
                        remaining -= n;
                        if(remaining > 0)
                                bcopy(cp+n, cp, remaining);
                        fcc -= n;
                        goto top; /* Ugly eh? ;process another `in-band' magic cookie!...*/
                    }
              }
            rcvstate = READING;
          }
          else{
            while(( rem = cc - (fbp - fibuf)) > 0){
                if((n = write(fdm, fbp, rem)) < 0)
                  continue;
                if(n == 0)
                  break;
                fbp += n;
     
          }
        if(n == 0)
                break;
        if(rem == 0)
                rcvstate = READING;
        }
        }
    }
    if(sigcaught == 0)
      kill(child_pid, SIGTERM);

    /* Return to caller....*/       
 
}

}



All times are GMT -5. The time now is 03:20 AM.