rlogLib.c
上传用户:nvosite88
上传日期:2007-01-17
资源大小:4983k
文件大小:27k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* rlogLib.c - remote login library */
  2. /* Copyright 1984 - 2002 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 03m,07may02,kbw  man page edits
  8. 03l,30apr02,fmk  notify shell of remote connection/disconnection
  9. 03k,15oct01,rae  merge from truestack ver 03l, base 03i (AE support)
  10. 03j,24may01,mil  Bump up rlogin task stack size to 8000.
  11. 03i,14mar99,jdi  doc: removed refs to config.h and/or configAll.h (SPR 25663).
  12. 03h,05oct98,jmp  doc: cleanup.
  13. 03g,30oct96,dgp  doc: change task names for rlogind() per SPR #5902
  14. 03f,09aug94,dzb  fixed activeFlag race with cleanupFlag (SPR #2050).
  15.                  made rlogindSocket global (SPR #1941).
  16.    +jpb  added username to rlogin "engaged" messages (SPR #3274).
  17. 03e,02may94,ms   increased stack size for SIMHPPA.
  18. 03d,24aug93,dvs  cleaned up removing pty from log fd list.
  19. 03c,23aug93,dvs  added logFdFromRlogin (SPR #2212).
  20. 03b,11aug93,jmm  Changed ioctl.h and socket.h to sys/ioctl.h and sys/socket.h
  21. 03a,02feb93,jdi  documentation tweak on configuration.
  22. 02z,20jan93,jdi  documentation cleanup for 5.1.
  23. 02y,19aug92,smb  Changed systime.h to sys/times.h.
  24. 02x,18jul92,smb  Changed errno.h to errnoLib.h.
  25. 02w,26may92,rrr  the tree shuffle
  26.   -changed includes to have absolute path from h/
  27. 02v,24apr92,rfs  Fixed flaky shell restart upon connection termination.
  28.                  The functions rlogInTask() and rlogExit() were changed.
  29.                  This is fixing SPR #1427.  Also misc ANSI noise.
  30. 02u,13dec91,gae  ANSI cleanup.
  31. 02t,19nov91,rrr  shut up some ansi warnings.
  32. 02s,14nov91,jpb  moved remCurIdSet to shellLogout (shellLib.c).
  33. 02r,04oct91,rrr  passed through the ansification filter
  34.                   -changed functions to ansi style
  35.   -changed READ, WRITE and UPDATE to O_RDONLY O_WRONLY and ...
  36.   -changed VOID to void
  37.   -changed copyright notice
  38. 02q,01aug91,yao  added to pass 6 args to excJobAdd() call.
  39. 02p,13may91,shl  undo'ed 02n.
  40. 02o,30apr91,jdi  documentation tweaks.
  41. 02n,29apr91,shl  added call to restore original machine name, user and
  42.  group ids (spr 916).
  43. 02m,05apr91,jdi  documentation -- removed header parens and x-ref numbers;
  44.  doc review by dnw.
  45. 02l,08mar91,jaa  documentation cleanup.
  46. 02k,04oct90.shl  fixed rlogExit() to restore original user and password.
  47. 02j,30sep90.del  added htons macros to port references
  48. 02i,08may90,shl  changed entry point of tRlogind back to rlogind.
  49. 02h,18apr90,shl  added shell security.
  50.  changed rlogind name to tRlogind.
  51. 02g,07apr89,ecs  bumped rlogTaskStackSize from 2000 to 5000 for SPARC.
  52. 02f,07jun89,gae  changed SOCKADDR back to "struct sockaddr".
  53. 02e,06jun88,dnw  changed taskSpawn/taskCreate args.
  54. 02d,30may88,dnw  changed to v4 names.
  55. 02c,28may88,dnw  changed to use shellOrigStdSet (...) instead of shellSetOrig...
  56.  changed not to use shellTaskId global variable.
  57. 02b,31mar88,gae  made it work with I/O system revision.
  58. 02a,26jan88,jcf  made kernel independent.
  59. 01x,19nov87,dnw  made rlogin set terminal 7-bit option so that "~." and
  60.    XON-XOFF will be reliably detected.
  61.  cleaned-up rlogin loop.
  62.  changed rlogind to wait for shell to exist before accepting
  63.    remote connections.
  64.    +gae  fixed problem of rlogin() exiting before a possible
  65.            rlogind session gets to finish.
  66. 01w,18nov87,ecs  lint.
  67.  added include of inetLib.h.
  68. 01v,15nov87,dnw  changed rlogInit() to return status.
  69. 01u,03nov87,ecs  documentation.
  70.      &   fixed bug in use of setsockopt().
  71.     dnw  changed rlogin() to accept inet address as well as host name.
  72.  changed to call shellLogoutInstall() instead of logoutInstall.
  73. 01t,24oct87,gae  changed setOrig{In,Out,Err}Fd() to shellSetOrig{In,Out,Err}().
  74.  made rlogindOut() exit on EOF from master pty fd.
  75.  made rlogin return VxWorks prompt when client disconnects.
  76.  made rlogInit() not sweat being called more than once.
  77.  added shellLock() to rlogind & rlogin to get exclusive use
  78.    of shell.
  79. 01s,20oct87,gae  added logging device for rlogin shell; made rlogInit()
  80.    create pty device.
  81. 01r,03oct87,gae  moved logout to usrLib.c and made rlogindExit() from rlogindIn.
  82.  removed gratuitious standard I/O ioctl()'s.
  83.  made "disconnection" cleaner by having shell do the restart.
  84. 01q,04sep87,llk  added logout().  Made rlogindSock global so that logout() could
  85.    access it.
  86.  changed rlogind so that it doesn't exit when an accept fails.
  87. 01p,22apr87,dnw  changed rlogin to turn on xon-xoff to terminal.
  88.  fixed handling of termination sequence "~.".
  89.  changed default priority of rlogin tasks from 100 to 2.
  90.  made priority and task ids be global variables so they
  91.    can be accessed from outside this module.
  92. 01o,02apr87,ecs  changed references to "struct sockaddr" to "SOCKADDR".
  93. 01n,27mar87,dnw  documentation.
  94. 01m,23mar87,jlf  documentation.
  95. 01l,27feb87,dnw  changed to spawn rlog tasks as UNBREAKABLE.
  96. 01k,20dec86,dnw  changed to use new call to remGetCurId().
  97.  changed old socket calls to normal i/o calls.
  98.  changed to not get include files from default directories.
  99.  added rlogInit ().
  100. 01j,27oct86,rdc  everything is now spawned in system mode with bigger stacks.
  101.  delinted.
  102. 01i,10oct86,gae  'remUser' made available through remGetCurId()...
  103.    included remLib.h.  Housekeeping.
  104. 01h,04sep86,jlf  documentation.
  105. 01g,31jul86,llk  uses new spawn
  106. 01f,27jul86,llk  added standard error fd which prints to the rlogin terminal.
  107.  Error messages go to standard error.
  108. 01e,07jul86,rdc  made rlogindInChild restart the shell after disconnect.
  109.  Documentation.
  110. 01d,19jun86,rdc  make rlogin close the socket after disconnect.
  111. 01c,18jun86,rdc  delinted.
  112. 01b,29apr86,rdc  rlogin now tries multiple local port numbers in its attempt
  113.  to connect to a remote host.
  114.  rlogind now uses KEEPALIVE option on sockets connected to
  115.  clients.
  116.  made rlogind unbreakable.
  117. 01a,02apr86,rdc  written.
  118. */
  119. /*
  120. DESCRIPTION
  121. This library provides a remote login facility for VxWorks based on the UNIX 
  122. `rlogin' protocol (as implemented in UNIX BSD 4.3).  On a VxWorks terminal, 
  123. this command gives users the ability to log in to remote systems on the 
  124. network.  
  125. Reciprocally, the remote login daemon, rlogind(), allows remote users to 
  126. log in to VxWorks.  The daemon is started by calling rlogInit(), which is 
  127. called automatically when INCLUDE_RLOGIN is defined.  The remote login 
  128. daemon accepts remote login requests from another VxWorks or UNIX system, 
  129. and causes the shell's input and output to be redirected to the remote user.
  130. Internally, rlogind() provides a tty-like interface to the remote
  131. user through the use of the VxWorks pseudo-terminal driver ptyDrv.
  132. INCLUDE FILES: rlogLib.h
  133. SEE ALSO:
  134. ptyDrv, telnetLib, UNIX BSD 4.3 manual entries for `rlogin', `rlogind', 
  135. and `pty'
  136. */
  137. #include "vxWorks.h"
  138. #include "sys/socket.h"
  139. #include "netinet/in.h"
  140. #include "inetLib.h"
  141. #include "ioLib.h"
  142. #include "remLib.h"
  143. #include "taskLib.h"
  144. #include "sys/times.h"
  145. #include "sockLib.h"
  146. #include "stdio.h"
  147. #include "unistd.h"
  148. #include "string.h"
  149. #include "errnoLib.h"
  150. #include "excLib.h"
  151. #include "logLib.h"
  152. #include "hostLib.h"
  153. #include "sysLib.h"
  154. #include "ptyDrv.h"
  155. #include "shellLib.h"
  156. #include "fcntl.h"
  157. #include "netLib.h"
  158. #define LOGIN_SERVICE 513
  159. #define STDIN_BUF_SIZE 200
  160. #define STDOUT_BUF_SIZE 200
  161. #define MAX_CONNECT_TRIES 5
  162. char *rlogShellName = "tShell"; /* task name we connect to */
  163. char *rlogTermType = "dumb/9600"; /* default terminal type */
  164. /* rlogin task parameters */
  165. int rlogTaskPriority = 2; /* task priority of rlogin tasks */
  166. int rlogTaskOptions = VX_SUPERVISOR_MODE | VX_UNBREAKABLE;
  167. #if    (CPU_FAMILY == SIMHPPA) || (CPU_FAMILY == SIMSPARCSUNOS)
  168. int rlogTaskStackSize   = 10000;         /* stack size of rlogin tasks */
  169. #else  /* CPU_FAMILY == SIMHPPA */
  170. int rlogTaskStackSize   = 8000;         /* stack size of rlogin tasks */
  171. #endif /* CPU_FAMILY == SIMHPPA */
  172. int rlogindId; /* rlogind task ID */
  173. int rlogInTaskId; /* rlogInTask task ID */
  174. int rlogOutTaskId; /* rlogOutTask task ID */
  175. int rlogChildTaskId; /* rlogChildTask task ID */
  176. int rlogindSocket; /* rlogind socket fd */
  177. /* externals */
  178. IMPORT int logFdFromRlogin; /* fd of pty for rlogin */
  179. /* local variables */
  180. LOCAL char *ptyRlogName  = "/pty/rlogin.";
  181. LOCAL char *ptyRlogNameM = "/pty/rlogin.M";
  182. LOCAL char *ptyRlogNameS = "/pty/rlogin.S";
  183. LOCAL BOOL activeFlag = FALSE; /* TRUE if there is an active connection */
  184. LOCAL BOOL cleanupFlag; /* TRUE if exit cleanup has occurred */
  185. LOCAL int rlogindM; /* rlogind master pty */
  186. LOCAL int rlogindS; /* rlogind slave pty */
  187. LOCAL int rloginSocket; /* rlogin socket */
  188. LOCAL int shellInFd; /* original console input */
  189. LOCAL int shellOutFd; /* original console output */
  190. LOCAL int shellErrFd; /* original console error output */
  191. /* forward declarations */
  192. void rlogind ();
  193. void rlogInTask ();
  194. void rlogOutTask ();
  195. void rlogChildTask ();
  196. /* forward static functions */
  197. static void rlogExit (BOOL usedLogout);
  198. static STATUS recvStr (int sd, char *buf);
  199. static void childTaskSpawn (int priority, int options, int stackSize);
  200. /*******************************************************************************
  201. *
  202. * rlogInit - initialize the remote login facility
  203. *
  204. * This routine initializes the remote login facility.  It creates a pty 
  205. * (pseudo tty) device and spawns rlogind().  If INCLUDE_RLOGIN is included,
  206. * rlogInit() is called automatically at boot time.
  207. *
  208. * VXWORKS AE PROTECTION DOMAINS
  209. * Under VxWorks AE, you can call this function from within the kernel 
  210. * protection domain only.  This restriction does not apply under non-AE 
  211. * versions of VxWorks.  
  212. *
  213. * RETURNS: OK or ERROR.
  214. *
  215. * SEE ALSO: ptyDrv
  216. */
  217. STATUS rlogInit (void)
  218.     {
  219.     static BOOL done; /* FALSE = not done */
  220.     if (done)
  221. {
  222. printErr ("rlogInit: already initialized.n");
  223. return (ERROR);
  224. }
  225.     else
  226. done = TRUE;
  227.     if (ptyDrv () == ERROR || ptyDevCreate (ptyRlogName, 1024, 1024) == ERROR)
  228. {
  229. printErr ("rlogInit: unable to create pty device.n");
  230. return (ERROR);
  231. }
  232.     rlogindId = taskSpawn ("tRlogind", rlogTaskPriority,
  233.    rlogTaskOptions, rlogTaskStackSize,
  234.    (FUNCPTR)rlogind, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  235.     if (rlogindId == ERROR)
  236. {
  237. printErr ("rlogInit: unable to spawn rlogind.n");
  238. return (ERROR);
  239. }
  240.     return (OK);
  241.     }
  242. /*******************************************************************************
  243. *
  244. * rlogind - the VxWorks remote login daemon
  245. *
  246. * This routine provides a facility for remote users to log in to VxWorks over
  247. * the network.  If INCLUDE_RLOGIN is defined, rlogind() is spawned by
  248. * rlogInit() at boot time.
  249. *
  250. * Remote login requests will cause `stdin', `stdout', and `stderr' to be
  251. * directed away from the console.  When the remote user disconnects,
  252. * `stdin', `stdout', and `stderr' are restored, and the shell is restarted.
  253. * The rlogind() routine uses the remote user verification protocol specified
  254. * by the UNIX remote shell daemon documentation, but ignores all the
  255. * information except the user name, which is used to set the VxWorks remote
  256. * identity (see the manual entry for iam()).
  257. *
  258. * The remote login daemon requires the existence of a pseudo-terminal
  259. * device, which is created by rlogInit() before rlogind() is spawned.  The
  260. * rlogind() routine creates two child processes, `tRlogInTask' and
  261. * `tRlogOutTask', whenever a remote user is logged in.  These processes exit
  262. * when the remote connection is terminated.
  263. *
  264. * VXWORKS AE PROTECTION DOMAINS
  265. * Under VxWorks AE, you can call this function from within the kernel 
  266. * protection domain only.  In addition, all arguments to this function can  
  267. * reference only that data which is valid in the kernel protection domain. 
  268. * This restriction does not apply under non-AE versions of VxWorks.  
  269. *
  270. * RETURNS: N/A
  271. *
  272. * SEE ALSO: rlogInit(), iam()
  273. */
  274. void rlogind (void)
  275.     {
  276.     char remUser [MAX_IDENTITY_LEN]; /* remote user trying to log in */
  277.     char curUser [MAX_IDENTITY_LEN]; /* current user already logged in */
  278.     char buf [STDIN_BUF_SIZE];
  279.     int optval;
  280.     struct sockaddr_in myAddress;
  281.     struct sockaddr_in clientAddress;
  282.     int clientAddrLen;
  283.     int masterFd;
  284.     int slaveFd;
  285.     int client;
  286.     int sd;
  287.     /* open a socket and wait for a client */
  288.     sd = socket (AF_INET, SOCK_STREAM, 0);
  289.     bzero ((char *) &myAddress, sizeof (myAddress));
  290.     myAddress.sin_family = AF_INET;
  291.     myAddress.sin_port   = htons (LOGIN_SERVICE);
  292.     if (bind (sd, (struct sockaddr *) &myAddress, sizeof (myAddress)) == ERROR)
  293. {
  294. printErr ("rlogind: bind failed.n");
  295. return;
  296. }
  297.     listen (sd, 1);
  298.     FOREVER
  299. {
  300. /* wait for shell to exist */
  301. while (taskNameToId (rlogShellName) == ERROR)
  302.     taskDelay (sysClkRateGet ());
  303. errnoSet (OK); /* clear errno for pretty i() display */
  304. /* now accept connection */
  305. clientAddrLen = sizeof (clientAddress);
  306. client = accept (sd, (struct sockaddr *)&clientAddress, &clientAddrLen);
  307. if (client == ERROR)
  308.     {
  309.     printErr ("rlogind: accept failed - status = 0x%x", errnoGet());
  310.     continue;
  311.     }
  312. /* turn on KEEPALIVE so if the client crashes, we'll know about it */
  313. optval = 1;
  314. setsockopt (client, SOL_SOCKET, SO_KEEPALIVE,
  315.     (char *)&optval, sizeof (optval));
  316. /* read in initial strings from remote rlogin */
  317. if ((recvStr (client, buf) == ERROR) ||     /* ignore stderr */
  318.     (recvStr (client, remUser) == ERROR) || /* get local user name */
  319.     (recvStr (client, buf) == ERROR) ||     /* ignore remote user name*/
  320.     (recvStr (client, buf) == ERROR))     /* ignore terminal stuff */
  321.     {
  322.     close (client);
  323.     continue;
  324.     }
  325. /* acknowlege connection */
  326. write (client, "", 1);
  327. /* check to see if there's already an active connection */
  328. if (activeFlag)
  329.     {
  330.     char msg [STDOUT_BUF_SIZE];
  331.     sprintf (msg, "rnSorry, this system is engaged by user: %s.rn",
  332. curUser);
  333.     write (client, msg, strlen (msg));
  334.     close (client);
  335.     continue;
  336.     }
  337. /* create the pseudo terminal:
  338.  * the master side is connected to the socket to the
  339.  * remote machine - two processes rlogInTask & rlogOutTask
  340.  * handle input and output.
  341.  */
  342. if ((masterFd = open (ptyRlogNameM, O_RDWR, 0)) == ERROR)
  343.     {
  344.     char *msg = "rnSorry, trouble with pty.rn";
  345.     printErr ("rlogind: error opening %sn", ptyRlogNameM);
  346.     write (client, msg, strlen (msg));
  347.     close (client);
  348.     continue;
  349.     }
  350. if ((slaveFd = open (ptyRlogNameS, O_RDWR, 0)) == ERROR)
  351.     {
  352.     char *msg = "rnSorry, trouble with pty.rn";
  353.     printErr ("rlogind: error opening %sn", ptyRlogNameS);
  354.     write (client, msg, strlen (msg));
  355.     close (client);
  356.     close (masterFd);
  357.     continue;
  358.     }
  359. if (!shellLock (TRUE))
  360.     {
  361.     char *msg = "rnSorry, shell is locked.rn";
  362.     printErr ("rlogind: user: %s tried to login.n", remUser);
  363.     write (client, msg, strlen (msg));
  364.     close (client);
  365.     close (masterFd);
  366.     close (slaveFd);
  367.     continue;
  368.     }
  369. /* setup the slave device to act like a terminal */
  370. ioctl (slaveFd, FIOOPTIONS, OPT_TERMINAL);
  371.         strcpy (curUser, remUser);
  372. printf ("nrlogind: This system *IN USE* via rlogin by user: %s.n",
  373.     curUser);
  374. shellLogoutInstall ((FUNCPTR)rlogExit, TRUE);
  375. activeFlag    = TRUE;
  376. rlogindSocket = client;
  377. rlogindM      = masterFd;
  378. rlogindS      = slaveFd;
  379. /* flush out pty device */
  380. ioctl (slaveFd, FIOFLUSH, 0 /*XXX*/);
  381. /* save the shell's standard I/O fd's so we can restore them later */
  382. shellInFd  = ioGlobalStdGet (STD_IN);
  383. shellOutFd = ioGlobalStdGet (STD_OUT);
  384. shellErrFd = ioGlobalStdGet (STD_ERR);
  385. /* set shell's standard I/O to pty device; add extra logging device */
  386. shellOrigStdSet (STD_IN,  slaveFd);
  387. shellOrigStdSet (STD_OUT, slaveFd);
  388. shellOrigStdSet (STD_ERR, slaveFd);
  389. logFdAdd (slaveFd);
  390. logFdFromRlogin = slaveFd; /* store pty fd for logFdSet() */
  391. /* Notify shell of remote connection */
  392. shellIsRemoteConnectedSet (TRUE);
  393. /* the shell is currently stuck in a read from the console,
  394.  * so restart it */
  395. excJobAdd (shellRestart, TRUE, 0, 0, 0, 0, 0);
  396. /* spawn the process which transfers data from the master pty
  397.  * to the socket;
  398.  * spawn the process which transfers data from the client socket
  399.  * to the master pty.
  400.  */
  401. if (((rlogOutTaskId = taskSpawn("tRlogOutTask", rlogTaskPriority,
  402. rlogTaskOptions, rlogTaskStackSize,
  403. (FUNCPTR)rlogOutTask, client, masterFd,
  404. 0, 0, 0, 0, 0, 0, 0, 0)) == ERROR) ||
  405.     ((rlogInTaskId = taskSpawn ("tRlogInTask", rlogTaskPriority,
  406. rlogTaskOptions, rlogTaskStackSize,
  407. (FUNCPTR)rlogInTask, client, masterFd,
  408. 0, 0, 0, 0, 0, 0, 0, 0)) == ERROR))
  409.     {
  410.     printErr ("rlogind: error spawning %s child - status = 0x%xn",
  411.       (rlogOutTaskId != ERROR) ? "output" : "input",
  412.       errnoGet ());
  413.     if (rlogOutTaskId != ERROR)
  414. taskDelete (rlogOutTaskId);
  415.     rlogExit (FALSE); /* try to do tidy clean-up */
  416.     }
  417. }
  418.     }
  419. /*******************************************************************************
  420. *
  421. * rlogOutTask - stdout to socket process
  422. *
  423. * This routine gets spawned by the rlogin daemon to move
  424. * data between the client socket and the pseudo terminal.
  425. * The task exits when the pty has been closed.
  426. *
  427. * NOMANUAL
  428. * but not LOCAL for i()
  429. */
  430. void rlogOutTask
  431.     (
  432.     FAST int sock,      /* socket to copy output to */
  433.     int ptyMfd          /* pty Master fd */
  434.     )
  435.     {
  436.     int n;
  437.     char buf [STDOUT_BUF_SIZE];
  438.     while ((n = read (ptyMfd, buf, sizeof (buf))) > 0)
  439. write (sock, buf, n);
  440.     }
  441. /*******************************************************************************
  442. *
  443. * rlogInTask - socket to stdin process
  444. *
  445. * This routine gets spawned by the rlogin daemon to move
  446. * data between the pseudo terminal and the client socket.
  447. * The task exits, calling rlogExit(), when the client disconnects.
  448. *
  449. * NOMANUAL
  450. * but not LOCAL for i()
  451. */
  452. void rlogInTask
  453.     (
  454.     FAST int sock,      /* socket to copy input from */
  455.     int ptyMfd          /* pty Master fd */
  456.     )
  457.     {
  458.     FAST int n;
  459.     char buf [STDIN_BUF_SIZE];
  460.     cleanupFlag = FALSE; /* exit cleanup has not been done... */
  461.     /* Loop, reading from the socket and writing to the pty. */
  462.     while ((n = read (sock, buf, sizeof (buf))) > 0)
  463.         write (ptyMfd, buf, n);
  464.     /* Exit and cleanup.  The above loop will exit when the socket is
  465.      * closed.  The socket can be closed as a result of the connection
  466.      * terminating from the remote host, or as a result of the logout()
  467.      * command issued to our shell.  When the logout() command is used,
  468.      * the rlogExit() routine below is called and the socket is explicitly
  469.      * closed.  In this case, there is no need to call rlogExit() again.
  470.      * We use the cleanupFlag to determine this case.  To summarize, if the
  471.      * cleanupFlag is set, we are here because the connection was terminated
  472.      * remotely and cleanup is required.
  473.      */
  474.     if (!cleanupFlag)
  475.         rlogExit (FALSE);
  476.     }
  477. /*******************************************************************************
  478. *
  479. * rlogExit - exit and cleanup for rlogind
  480. *
  481. * This is the support routine for logout().
  482. * The client socket is closed, shell standard I/O is redirected
  483. * back to the console, and the shell is restarted.
  484. */
  485. LOCAL void rlogExit
  486.     (
  487.     BOOL usedLogout    /* true if called by logout() */
  488.     )
  489.     {
  490.     /* This routine is called either as a result of the logout() command
  491.      * being issued from the shell, or from the rlogInTask above.  It is
  492.      * therefore run in the context of the shell or rlogInTask.  The
  493.      * caller indicates itself to us by the usedLogout argument.  The
  494.      * state of this argument affects our behavior, as explained below.
  495.      */
  496.     cleanupFlag = TRUE; /* release rlogInTask() from duty */
  497.     shellLogoutInstall ((FUNCPTR) NULL, 0);     /* uninstall logout function */
  498.     if (logFdFromRlogin != NONE)
  499. {
  500.      logFdDelete (logFdFromRlogin);          /* cancel extra log device */
  501.      logFdFromRlogin = NONE; /* reset fd */
  502. }
  503.     shellOrigStdSet (STD_IN,  shellInFd);       /* restore shell's stnd I/O */
  504.     shellOrigStdSet (STD_OUT, shellOutFd);
  505.     shellOrigStdSet (STD_ERR, shellErrFd);
  506.     shellLock (FALSE);                          /* unlock shell */
  507.     
  508.     /* Notify shell of remote disconnection */
  509.     shellIsRemoteConnectedSet (FALSE);
  510.     
  511.     write (rlogindSocket, "rn", 2);
  512.     close (rlogindSocket);                      /* close the socket */
  513.     /* For typical remote sessions, there is no need to restart the shell.
  514.      * If we are in shell context, simply restoring the standard I/O
  515.      * descriptors is enough to get the shell back on track upon return
  516.      * from this function.  If we are in rlogInTask context, the closing
  517.      * of the pty device will cause the shell to unblock from its read()
  518.      * and do subsequent I/O from the restored descriptors.
  519.      * However, problems can occur upon logout if the remote user has
  520.      * disabled the line editor and/or put the pty device in raw mode.
  521.      * The problem caused is that the shell does not resume properly.
  522.      * It is therefore deemed prudent to always restart the shell, thereby
  523.      * avoiding any funny business.
  524.      *
  525.      * The previous version attempted to send a ctrl-D up the pty device
  526.      * to wakeup and restart the shell.  Unfortunately, ctrl-D only has
  527.      * special meaning when the device is in line mode, and hence did
  528.      * not work in raw mode.
  529.      *
  530.      * The pty device is closed after the shell is restarted, when called
  531.      * from rlogInTask, to avoid waking the existing shell and causing an
  532.      * additional prompt to appear on the console.
  533.      */
  534.     if (usedLogout)                             /* called from shell */
  535.         {
  536.         close (rlogindM);
  537.         close (rlogindS);
  538.         activeFlag = FALSE; /* allow new connection */
  539.         taskRestart (0);                        /* never returns */
  540.         }
  541.     else                                        /* called from rlogInTask */
  542.         {
  543.         excJobAdd (shellRestart, FALSE, 0, 0, 0, 0, 0);
  544.         close (rlogindM);
  545.         close (rlogindS);
  546.         activeFlag = FALSE; /* allow new connection */
  547.         }
  548.     }
  549. /*******************************************************************************
  550. *
  551. * recvStr - receive a null terminated string from a socket
  552. *
  553. * Similar to fioRdString, but for sockets.
  554. *
  555. * RETURNS: OK or ERROR.
  556. */
  557. LOCAL STATUS recvStr
  558.     (
  559.     FAST int sd,        /* socket */
  560.     FAST char *buf      /* where to put the string */
  561.     )
  562.     {
  563.     do
  564. {
  565. if (read (sd, buf, 1) != 1)
  566.     return (ERROR);
  567. }
  568.     while (*(buf++) != EOS);
  569.     return (OK);
  570.     }
  571. /*******************************************************************************
  572. *
  573. * childTaskSpawn - spawn rlogChildTask via netJob queue
  574. *
  575. * RETURNS: N/A
  576. */
  577. LOCAL void childTaskSpawn
  578.     (
  579.     int priority,
  580.     int options,
  581.     int stackSize
  582.     )
  583.     {
  584.     rlogChildTaskId = taskSpawn ("tRlogChildTask", priority, options,
  585.  stackSize, (FUNCPTR)rlogChildTask,
  586.  0,0,0,0,0,0,0,0,0,0);
  587.     if (rlogChildTaskId == ERROR)
  588.         {
  589.         printErr ("rlogin: trouble spawning child - status = 0x%xn",
  590.   errnoGet ());
  591.         close (rloginSocket);
  592. }
  593.     }
  594. /*******************************************************************************
  595. *
  596. * rlogin - log in to a remote host
  597. *
  598. * This routine allows users to log in to a remote host.  It may be called from
  599. * the VxWorks shell as follows:
  600. * .CS
  601. *    -> rlogin "remoteSystem"
  602. * .CE
  603. * where <remoteSystem> is either a host name, which has been previously added
  604. * to the remote host table by a call to hostAdd(), or an Internet address in
  605. * dot notation (e.g., "90.0.0.2").  The remote system will be logged into
  606. * with the current user name as set by a call to iam().
  607. *
  608. * The user disconnects from the remote system by typing:
  609. * .CS
  610. *    ~.
  611. * .CE
  612. * as the only characters on the line, or by simply logging out from the remote
  613. * system using logout().
  614. *
  615. * RETURNS:
  616. * OK, or ERROR if the host is unknown, no privileged ports are available,
  617. * the routine is unable to connect to the host, or the child process cannot
  618. * be spawned.
  619. *
  620. * SEE ALSO: iam(), logout()
  621. */
  622. STATUS rlogin
  623.     (
  624.     char *host          /* name of host to connect to */
  625.     )
  626.     {
  627.     char remUser [MAX_IDENTITY_LEN];
  628.     char remPasswd [MAX_IDENTITY_LEN];
  629.     struct sockaddr_in hostAddr;
  630.     int port;
  631.     char ch;
  632.     int quitFlag;
  633.     int status;
  634.     int nTries;
  635.     /* connect to host */
  636.     if (((hostAddr.sin_addr.s_addr = hostGetByName (host)) == ERROR) &&
  637.         ((hostAddr.sin_addr.s_addr = inet_addr (host)) == ERROR))
  638. {
  639. printErr ("rlogin: unknown host.n");
  640. return (ERROR);
  641. }
  642.     hostAddr.sin_family = AF_INET;
  643.     hostAddr.sin_port   = htons (LOGIN_SERVICE);
  644.     remCurIdGet (remUser, remPasswd);
  645.     port   = 1000;
  646.     status = ERROR;
  647.     for (nTries = 0; status == ERROR && nTries < MAX_CONNECT_TRIES; nTries++)
  648. {
  649. if ((rloginSocket = rresvport (&port)) == ERROR)
  650.     {
  651.     printErr ("rlogin: no available privileged ports.n");
  652.     return (ERROR);
  653.     }
  654. status = connect (rloginSocket, (struct sockaddr *)&hostAddr,
  655.     sizeof(hostAddr));
  656. port--;
  657. }
  658.     if (status == ERROR)
  659. {
  660. printErr ("rlogin: could not connect to host.n");
  661. close (rloginSocket);
  662. return (ERROR);
  663. }
  664.     /* send a null (no seperate STDERR) */
  665.     write (rloginSocket, "", 1);
  666.     /* send the local and remote user names */
  667.     write (rloginSocket, remUser, strlen (remUser) + 1);
  668.     write (rloginSocket, remUser, strlen (remUser) + 1);
  669.     /* send the terminal type */
  670.     write (rloginSocket, rlogTermType, strlen (rlogTermType) + 1);
  671.     /* spawn a process to handle stdin */
  672.     status = netJobAdd ((FUNCPTR)childTaskSpawn, rlogTaskPriority,
  673.                         rlogTaskOptions, rlogTaskStackSize, 0, 0);
  674.     if (status != OK) /* netJob queue overflow, error printed by panic */
  675. {
  676.         close (rloginSocket);
  677. return (ERROR);
  678. }
  679.     /* force shell to be locked, shellLock is FALSE if already locked */
  680.     shellLock (TRUE);
  681.     /* set console to RAW mode except with XON-XOFF and 7 bit */
  682.     ioctl (STD_IN, FIOOPTIONS, OPT_TANDEM | OPT_7_BIT);
  683.     quitFlag = 0;
  684.     while ((rloginSocket != ERROR) && (read (STD_IN, &ch, 1) == 1))
  685. {
  686. /* track input of "<CR>~.<CR>" to terminate connection */
  687. if ((quitFlag == 0) && (ch == '~'))
  688.     quitFlag = 1;
  689. else if ((quitFlag == 1) && (ch == '.'))
  690.     quitFlag = 2;
  691. else if ((quitFlag == 2) && (ch == 'r'))
  692.     break; /* got "<CR>~.<CR>" */
  693. else
  694.     quitFlag = (ch == 'r') ? 0 : -1;
  695. write (rloginSocket, &ch, 1);
  696. }
  697.     /* wait for other tasks to finish up, i.e. rlogind */
  698.     taskDelay (sysClkRateGet () / 2);
  699.     if (rloginSocket != ERROR)
  700. {
  701. taskDelete (rlogChildTaskId);
  702. close (rloginSocket);
  703. }
  704.     /* reset console */
  705.     ioctl (STD_IN, FIOOPTIONS, OPT_TERMINAL);
  706.     printf ("nClosed connection.n");
  707.     shellLock (FALSE);
  708.     return (OK);
  709.     }
  710. /*******************************************************************************
  711. *
  712. * rlogChildTask - rlogin child
  713. *
  714. * This routine gets spawned by rlogin() to read data from
  715. * the rloginSocket and write it to stdout.
  716. * The task exits when the client disconnects;
  717. * rlogin is informed by setting rloginSocket to ERROR.
  718. *
  719. * NOMANUAL
  720. * but not LOCAL for i()
  721. */
  722. void rlogChildTask (void)
  723.     {
  724.     char buf [STDOUT_BUF_SIZE];
  725.     int n;
  726.     while ((n = read (rloginSocket, buf, sizeof (buf))) > 0)
  727. write (STD_OUT, buf, n);
  728.     close (rloginSocket);
  729.     /* indicate that client side caused termination,
  730.      * and stop rlogin from reading stdin */
  731.     rloginSocket = ERROR;
  732.     ioctl (STD_IN, FIOCANCEL, 0 /*XXX*/);
  733.     }