# Need help with C socket daemon



## maudib (Jun 7, 2013)

Hi*,*

I have a few questions 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 programming 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 this:


```
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 its own session. Then the slave-side becomes the CTTY of anything executed in this child. Also dup2 is then called to set the stdin, stdout, stderr to the slave's file descriptor (returned from open()ing the slave-side, as explained above). 

Thus, *I* thought, /bin/login would have its stdin, stdout and stderr 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 *Free*BSD version of rlogind.c):


```
/*
 * 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.
 */
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....*/         
  
}

}
```

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 vi*ce* 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' network programming 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 kind of crazy (as is wanting to code such an application as rlogind!).

Any help/suggestions would be gratefully received*.*

Thank you very much in advance.


----------



## maudib (Jun 7, 2013)

And yes the firewall is off on the server when I test the program. Also I don't use `rcmd`. I just write the username, read it on the server. Then the server passes this name to /bin/login. I have changed the code in the original post to be something that should work better, but it doesn't make any difference to the outcome of running the program.


----------



## maudib (Jul 1, 2013)

How extremely embarrassing. The problem was *I* was returning from the parent after the child had been forked to do the `execle` of /usr/bin/login so that *I* wasn't `wait()`ing for the child or calling a function to handle the reads/writes to/from the socket/pty(ptmx). 
Sorry[](again) for posting such a trivial problem!


----------



## ta0kira (Jul 3, 2013)

maudib said:
			
		

> ```
> if([B][U][color="Red"]excel[/color][/U][/B]("/bin/login", "login", "-p", "-h", hp->h_name, "-f", user_name, (char *)0)== -1)
> perror("/bin/login error");
> ```


Is this a spell-check correction, or did you type parts of the line directly into your post? It helps to post the same code that you're compiling.

Kevin Barry


----------



## maudib (Jul 4, 2013)

*S*orry*,* *I* was working on Linux as well*,* so forgot to write /usr/bin/login instead of /bin/login. This question has been solved as indicated above. Thanks for the reply though!


----------

