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

VxWorks

开发平台:

C/C++

  1. /* telnetdLib.c - telnet server library */
  2. /* Copyright 1984 - 2002 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 03n,06jun02,elr  Documentation (SPR #78015)
  8. 03m,07may02,kbw  man page edits
  9. 03l,02may02,elr  Removed telnetdMutexSem in telnetdParserSet()  (SPR #76641)
  10.                  Corrected uninitialized session data pointers 
  11.                  Removed superfluous telnetdInitialized = FALSE
  12. 03k,30apr02,elr  Moved password authentication to telnetd context (SPR 30687)
  13.                  Corrected problems with messy session disconnects leaving 
  14.                       many resources still open (SPR 75891) (SPR 72752) (SPR 5059)
  15.                  Corrected security problems
  16.                  Moved the context of authentication/login to telnetd from shell
  17.                  Improved documentation and included an example of a user shell
  18.                  Simplified code as a result of the static creation merge 
  19.                     version 03h
  20.                  Added macro for debug messages
  21. 03j,19oct01,rae  merge from truestack ver03j, base 03f (memory leak, doc)
  22. 03i,24may01,mil  Bump up telnet task stack size to 8000.
  23. 03h,14feb01,spm  merged from version 03f of tor2_0_x branch (base 03e):
  24.                  general overhaul of telnet server (SPR #28675)
  25. 03g,08nov99,pul  T2 cumulative patch 2
  26. 03f,30jun99,cno  Enable changing the telnet port number (SPR27680)
  27. 03e,14mar99,jdi  doc: removed refs to config.h and/or configAll.h (SPR 25663).
  28. 03d,05oct98,jmp  doc: cleanup.
  29. 03c,30oct96,dgp  doc: change task names for telnetd() per SPR #5901
  30. 03b,09aug94,dzb  fixed activeFlag race with cleanupFlag (SPR #2050).
  31.                  made telnetdSocket global (SPR #1941).
  32.  added logFdFromRlogin (SPR #2212).
  33. 03a,02may94,ms   increased stack size for SIMHPPA.
  34. 02z,11aug93,jmm  Changed ioctl.h and socket.h to sys/ioctl.h and sys/socket.h
  35. 02y,01feb93,jdi  documentation cleanup for 5.1.
  36. 02x,18jul92,smb  Changed errno.h to errnoLib.h.
  37. 02w,26may92,rrr  the tree shuffle
  38.   -changed includes to have absolute path from h/
  39. 02v,24apr92,rfs  Fixed flaky shell restart upon connection termination.
  40.                  The functions telnetInTask() and telnetdExit() were changed.
  41.                  This is fixing SPR #1427.  Also misc ANSI noise.
  42. 02u,13dec91,gae  ANSI cleanup.
  43. 02t,14nov91,jpb  moved remCurIdSet to shellLogout (shellLib.c).
  44. 02s,04oct91,rrr  passed through the ansification filter
  45.                   -changed functions to ansi style
  46.   -changed includes to have absolute path from h/
  47.   -fixed #else and #endif
  48.   -changed READ, WRITE and UPDATE to O_RDONLY O_WRONLY and ...
  49.   -changed VOID to void
  50.   -changed copyright notice
  51. 02r,01aug91,yao  fixed to pass 6 args to excJobAdd() call.
  52. 02q,13may91,shl  undo'ed 02o.
  53. 02p,30apr91,jdi  documentation tweaks.
  54. 02o,29apr91,shl  added call to restore original machine name, user and
  55.  group ids (spr 916).
  56. 02n,05apr91,jdi  documentation -- removed header parens and x-ref numbers;
  57.  doc review by dnw.
  58. 02m,24mar91,jdi  documentation cleanup.
  59. 02l,05oct90,shl  fixed telnetExit() to restore original user and password.
  60. 02k,02oct90,hjb  added a call to htons() where needed.
  61. 02j,08aug90,dnw  changed declaration of tnInput from void to int.
  62.  added forward declaration of setMode().
  63. 02i,07may90,shl  changed entry point of tTelnetd back to telnetd.
  64. 02h,18apr90,shl  added shell security.
  65.  changed telnetd name to tTelnetd.
  66. 02g,20aug89,gae  bumped telnetTaskStackSize from 1500 to 5000 for SPARC.
  67. 02f,29sep88,gae  documentation.
  68. 02e,06jun88,dnw  changed taskSpawn/taskCreate args.
  69. 02d,30may88,dnw  changed to v4 names.
  70. 02c,28may88,dnw  changed to use shellOrigStdSet (...) instead of shellSetOrig...
  71.  changed not to use shellTaskId global variable.
  72. 02b,01apr88,gae  made it work with I/O system revision.
  73. 02a,27jan88,jcf  made kernel independent.
  74. 01g,14dec87,dnw  fixed bug in telnetdIn() that caused system crashes.
  75. 01f,19nov87,dnw  changed telnetd to wait for shell to exist before accepting
  76.    remote connections.
  77. 01e,17nov87,ecs  lint.
  78. 01d,04nov87,ecs  documentation.
  79.      &   fixed bug in use of setsockopt().
  80.     dnw  changed to call shellLogoutInstall() instead of logoutInstall.
  81. 01c,24oct87,gae  changed setOrig{In,Out,Err}Fd() to shellSetOrig{In,Out,Err}().
  82.  made telnetdOut() exit on EOF from master pty fd.
  83.  made telnetInit() not sweat being called more than once.
  84.  added shellLock() to telnetd to get exclusive use of shell.
  85. 01g,20oct87,gae  added logging device for telnet shell; made telnetInit()
  86.    create pty device.
  87. 01f,05oct87,gae  made telnetdExit() from telnetdIn() - used by logout().
  88.  removed gratuitous standard I/O ioctl's.
  89.  made "disconnection" cleaner by having shell do restart.
  90. 01e,26jul87,dnw  changed default priority of telnet tasks from 100 to 2.
  91.  changed task priority and ids to be global variables so
  92.    they can be accessed from outside this module.
  93. 01d,04apr87,dnw  de-linted.
  94. 01c,27mar87,dnw  documentation
  95.  fixed bug causing control sequences from remote to be
  96.    misinterpreted.
  97.  added flushing of pty in case anything was left before
  98.    remote login.
  99. 01b,27feb87,dnw  changed to spawn telnet tasks UNBREAKABLE.
  100. 01a,20oct86,dnw  written.
  101. */
  102. /*
  103. DESCRIPTION
  104. The telnet protocol enables users on remote systems to login to VxWorks.
  105. This library implements a telnet server which accepts remote telnet login
  106. requests and transfers input and output data between a command interpreter
  107. and the remote user. The default configuration redirects the input and output
  108. from the VxWorks shell if available. The telnetdParserSet() routine allows
  109. the installation of an alternative command interpreter to handle the remote
  110. input and provide the output responses. If INCLUDE_SHELL is not defined,
  111. installing a command interpreter is required.
  112. The telnetdInit() routine initializes the telnet service when INCLUDE_TELNET
  113. is defined. If INCLUDE_SHELL is also defined, the telnetdStart() routine
  114. automatically starts the server. Client sessions will connect to the shell,
  115. which only supports one client at a time.
  116. VXWORKS AE PROTECTION DOMAINS
  117. Under VxWorks AE, the telnet server runs within the kernel protection domain 
  118. only.  This restriction does not apply under non-AE versions of VxWorks.  
  119. INTERNAL
  120. When connecting remote users to the VxWorks shell, the pseudo-terminal
  121. driver ptyDrv provides data transfer between the telnet server and the shell.
  122. INCLUDE FILES: telnetLib.h
  123. SEE ALSO: rlogLib
  124. */
  125. #include "vxWorks.h"
  126. #include "sys/types.h"
  127. #include "sys/socket.h"
  128. #include "netinet/in.h"
  129. #include "ioLib.h"
  130. #include "taskLib.h"
  131. #include "telnetLib.h"
  132. #include "stdlib.h"
  133. #include "unistd.h"
  134. #include "errnoLib.h"
  135. #include "string.h"
  136. #include "stdio.h"
  137. #include "fcntl.h"
  138. #include "sockLib.h"
  139. #include "shellLib.h"
  140. #include "remLib.h"
  141. #include "sysLib.h"
  142. #include "tickLib.h"
  143. #include "ptyDrv.h"
  144. #include "logLib.h"
  145. #include "excLib.h"
  146. #define STDIN_BUF_SIZE 512
  147. #define STDOUT_BUF_SIZE 512
  148. /* telnet input states */
  149. #define TS_DATA 0
  150. #define TS_IAC 1
  151. #define TS_CR 2
  152. #define TS_BEGINNEG 3
  153. #define TS_ENDNEG 4
  154. #define TS_WILL 5
  155. #define TS_WONT 6
  156. #define TS_DO 7
  157. #define TS_DONT 8
  158. /* The maximum string length of pty i/o task name */
  159. #define IO_TASK_NAME_MAX_LEN 128 
  160. /* Pseudo TTY buffers (input and output) */
  161. #define PTY_BUFFER_SIZE 1024
  162. /* debugging definition for a log messages */
  163. #define TELNETD_DEBUG(string,  param1, param2, param3, param4, param5, param6)
  164.    { 
  165.    if (_func_logMsg != NULL) 
  166.       (* _func_logMsg) (string, param1, param2, param3, param4, param5, 
  167.        param6);
  168.    }
  169. /* global variables */
  170. #ifndef DEBUG
  171. int telnetTaskOptions   = VX_SUPERVISOR_MODE | VX_UNBREAKABLE;
  172. #else
  173. int telnetTaskOptions   = VX_SUPERVISOR_MODE;
  174. #endif
  175. #if    (CPU_FAMILY == SIMHPPA) || (CPU_FAMILY == SIMSPARCSUNOS)
  176. int telnetTaskStackSize = 10000;
  177. #else  /* CPU_FAMILY == SIMHPPA */
  178. int telnetTaskStackSize = 8000;
  179. #endif /* CPU_FAMILY == SIMHPPA */
  180. int telnetTaskPriority  = 55; /* priority of telnet tasks */
  181. int telnetdCurrentClients = 0;
  182. /* local variables */
  183. /* 
  184.  * telnetdSessionList is a pointer to a linked list of active sessions.
  185.  * This is maintained for cleanup during exit 
  186.  */
  187. LOCAL LIST  telnetdSessionList;
  188. LOCAL BOOL telnetdTaskFlag = TRUE;    /* Create tasks when client connects? */
  189. /* telnetdTaskList - an array of all sessions (active or inactive) */
  190. LOCAL TELNETD_TASK_DATA * telnetdTaskList; 
  191. LOCAL int telnetdMaxClients = 1; /* Default limit for simultaneous sessions. */
  192. LOCAL int telnetdTaskId;        /* task ID of telnet server task */
  193. LOCAL int telnetdServerSock;
  194. LOCAL SEM_ID telnetdMutexSem;
  195. LOCAL BOOL telnetdInitialized = FALSE;  /* Server initialized? */
  196. LOCAL BOOL telnetdParserFlag = FALSE;  /* Parser access task registered? */
  197. LOCAL BOOL telnetdStartFlag = FALSE;    /* Server started? */
  198. LOCAL TBOOL myOpts [256]; /* current option settings - this side */
  199. LOCAL TBOOL remOpts [256]; /* current option settings - other side */
  200. LOCAL BOOL raw; /* TRUE = raw mode enabled */
  201. LOCAL BOOL echo; /* TRUE = echo enabled */
  202. LOCAL FUNCPTR telnetdParserControl = NULL; /* Accesses command interpreter. */
  203. LOCAL BOOL remoteInitFlag = FALSE;  /* No remote users have connected. */
  204. LOCAL char *ptyRemoteName  = "/pty/rmt";    /* terminal for remote user */
  205. LOCAL int masterFd;  /* master pty for remote users */
  206. /* forward declarations */
  207. void telnetdExit (UINT32 sessionId);
  208. LOCAL void telnetdTaskDelete (int numTasks);
  209. LOCAL int tnInput (int state, int slaveFd, int clientSock, int inputFd, 
  210.                    char *buf, int n);
  211. LOCAL STATUS remDoOpt (int opt, int slaveFd, BOOL enable, int clientSock, 
  212.                        BOOL remFlag);
  213. LOCAL STATUS localDoOpt (int opt, int slaveFd, BOOL enable, int clientSock, 
  214.                          BOOL remFlag);
  215. LOCAL void setMode (int slaveFd, int telnetOption, BOOL enable);
  216. LOCAL STATUS telnetdIoTasksCreate (TELNETD_SESSION_DATA *pSlot);
  217. LOCAL STATUS telnetdSessionPtysCreate (TELNETD_SESSION_DATA *pSlot);
  218. LOCAL TELNETD_SESSION_DATA *telnetdSessionAdd (void);
  219. LOCAL void telnetdSessionDisconnect (TELNETD_SESSION_DATA *pSlot, 
  220.                                      BOOL pSlotdeAllocate);
  221. LOCAL void telnetdSessionDisconnectFromShell (TELNETD_SESSION_DATA *pSlot);
  222. LOCAL void telnetdSessionDisconnectFromRemote (TELNETD_SESSION_DATA *pSlot);
  223. /*******************************************************************************
  224. *
  225. * telnetdInit - initialize the telnet services
  226. *
  227. * This routine initializes the telnet server, which supports remote login
  228. * to VxWorks via the telnet protocol. It is called automatically when the
  229. * configuration macro INCLUDE_TELNET is defined. The telnet server supports
  230. * simultaneous client sessions up to the limit specified by the
  231. * TELNETD_MAX_CLIENTS setting provided in the <numClients> argument. The
  232. * <staticFlag> argument is equal to the TELNETD_TASKFLAG setting. It allows
  233. * the server to create all of the secondary input and output tasks and allocate
  234. * all required resources in advance of any connection. The default value of
  235. * FALSE causes the server to spawn a task pair and create the associated data
  236. * structures after each new connection.
  237. *
  238. * VXWORKS AE PROTECTION DOMAINS
  239. * Under VxWorks AE, you can call this function from within the kernel 
  240. * protection domain only.  This restriction does not apply under non-AE 
  241. * versions of VxWorks.  
  242. *
  243. * RETURNS: OK, or ERROR if initialization fails
  244. */
  245. STATUS telnetdInit
  246.     (
  247.     int numClients, /* maximum number of simultaneous sessions */
  248.     BOOL staticFlag /* TRUE: create all tasks in advance of any clients */
  249.     )
  250.     {
  251.     int count;
  252.     int result;
  253.     if (telnetdInitialized)
  254.         return (OK);
  255.     if (numClients <= 0)
  256.         return (ERROR);
  257.     /* 
  258.      * If static initialization is selected,  
  259.      *  then we must have a parser control installed 
  260.      */
  261.     if (staticFlag && (telnetdParserControl == NULL))
  262.         {
  263.         TELNETD_DEBUG ("telnetd: A shell has not been installed - can't initialize library. errno:%#xn", 
  264.                         errno, 0, 0, 0, 0, 0);
  265.         return (ERROR);
  266.         }
  267.     telnetdMutexSem = semMCreate (SEM_Q_PRIORITY | SEM_DELETE_SAFE | 
  268.                                   SEM_INVERSION_SAFE );  
  269.     if (telnetdMutexSem == NULL)
  270.         return (ERROR);
  271.     if (remoteInitFlag == FALSE)
  272.         {
  273.         /* Create pty device for all remote sessions. */
  274.         if (ptyDrv () == ERROR)
  275.             {
  276.             TELNETD_DEBUG ("telnetd: Unable to initialize ptyDrv().  errno:%#xn", 
  277.                                errno, 0, 0, 0, 0, 0);
  278.             return ERROR;
  279.             }
  280.         remoteInitFlag = TRUE;   /* Disable further device creation. */
  281.         }
  282.     telnetdTaskFlag = staticFlag;   /* Create input/output tasks early? */
  283.     telnetdMaxClients = numClients;
  284.     telnetdTaskList = (TELNETD_TASK_DATA *)calloc (telnetdMaxClients,
  285.                                                   sizeof (TELNETD_TASK_DATA));
  286.     if (telnetdTaskList == NULL)
  287.         {
  288.         semDelete (telnetdMutexSem);
  289.         return (ERROR);
  290.         }
  291.     /* Allocate all of the session data structures and initialize them */
  292.     for (count = 0; count < numClients; count++)
  293.         {
  294.         telnetdTaskList[count].pSession = 
  295.             (TELNETD_SESSION_DATA *)calloc (sizeof (TELNETD_SESSION_DATA), 
  296.                                                 1);
  297.         if (telnetdTaskList[count].pSession == NULL)
  298.             {
  299.             telnetdTaskDelete (count);
  300.             return (ERROR);
  301.             }
  302.         /* 
  303.          * Initialize all elements of the structure to sane values.
  304.          * Note that we use  '-1' is used in some cases so that we 
  305.          *  can differentiate from valid i/o file descriptors such as stdin.
  306.          *  Also we need invalid task id's for initialization so we can
  307.          *  differentiate from taskIdSelf() since 0 is implied as our taskId
  308.          */
  309.         telnetdTaskList[count].pSession->socket         = -1;
  310.         telnetdTaskList[count].pSession->inputFd        = -1;            
  311.         telnetdTaskList[count].pSession->outputFd       = -1;          
  312.         telnetdTaskList[count].pSession->slaveFd        = -1;          
  313.         telnetdTaskList[count].pSession->outputTask     = -1;      
  314.         telnetdTaskList[count].pSession->inputTask      = -1;      
  315.         telnetdTaskList[count].pSession->parserControl  = 0; 
  316.         telnetdTaskList[count].pSession->busyFlag       = FALSE;
  317.         telnetdTaskList[count].pSession->loggedIn       = FALSE;
  318.         /* 
  319.          * Static initialization has all resources and tasks created up front.
  320.          * Create and spawn all resources and associate them in the session and task structures.
  321.          */
  322.         if (telnetdTaskFlag)
  323.             {
  324.             /* 
  325.              * Spawn static input/output tasks for each possible connection.
  326.              * In this configuration, the command interpreter currently
  327.              * assigned can never be changed.
  328.              *
  329.              * New entries are identical in construction to the 
  330.              * 'one-at-a-time', dynamic telnet session entries.  
  331.              * 
  332.              * The spawned tasks will pend on a semaphore which signifies 
  333.              * the acceptance of a new socket connection.
  334.              *
  335.              * The session entry will be filled in when the connection 
  336.              * is accepted.
  337.              */
  338.             if ( telnetdSessionPtysCreate (telnetdTaskList[count].pSession) == 
  339.                  ERROR)
  340.                 {
  341.                 TELNETD_DEBUG ("telnetd: Unable to create all sessions in advance. errno:%#xn", 
  342.                         errno, 0, 0, 0, 0, 0);
  343.                 telnetdTaskDelete (count);
  344.                 return ERROR;
  345.                 }
  346.             if (telnetdIoTasksCreate (telnetdTaskList[count].pSession) == ERROR)
  347.                 {
  348.                 TELNETD_DEBUG ("telnetd: error spawning i/o tasks - can't initialize library. errno:%#xn", 
  349.                                errno, 0, 0, 0, 0, 0);
  350.                 telnetdTaskDelete (count);
  351.                 return ERROR;
  352.                 }
  353.             /*
  354.              * Announce to the installed parser control routine that 
  355.              *  we have a new session installed.   No connection has been 
  356.              *  established to this session at this point.
  357.              */
  358.     
  359.             result = (*telnetdParserControl) (REMOTE_INIT, 
  360.                                               (UINT32)telnetdTaskList[count].pSession,
  361.                                               telnetdTaskList[count].pSession->slaveFd);
  362.             /* Did we initialize the shell? */
  363.             if (result == ERROR) /* No,  must have failed */
  364.                 {
  365.                 TELNETD_DEBUG ("telnetd: error pre-initializing shell. Note:vxWorks shell does not support static initialization! errno:%#xn", 
  366.                                errno, 0, 0, 0, 0, 0);
  367.                 telnetdTaskDelete (count);
  368.                 return ERROR;
  369.                 }
  370.             /*
  371.              * File descriptors are available. Save the corresponding
  372.              * parser control routine.
  373.              */
  374.             telnetdTaskList[count].pSession->parserControl = 
  375.                 telnetdParserControl;
  376.             }
  377.         }
  378.     telnetdInitialized = TRUE;
  379.     return (OK);
  380.     }
  381. /*******************************************************************************
  382. *
  383. * telnetdParserSet - specify a command interpreter for telnet sessions
  384. *
  385. * This routine provides the ability to handle telnet connections using
  386. * a custom command interpreter or the default VxWorks shell. It is
  387. * called automatically during system startup (when the configuration macro
  388. * INCLUDE_TELNET is defined) to connect clients to the command interpreter
  389. * specified in the TELNETD_PARSER_HOOK parameter. The command interpreter in 
  390. * use when the telnet server start scan never be changed.
  391. *
  392. * The <pParserCtrlRtn> argument provides a routine using the following
  393. * interface:
  394. * .CS
  395. * STATUS parserControlRtn
  396. *     (
  397. *     int telnetdEvent,/@ start or stop a telnet session @/
  398. *     UINT32 sessionId,/@ a unique session identifier @/
  399. *     int ioFd         /@ file descriptor for character i/o @/
  400. *     )
  401. * .CE
  402. *
  403. * The telnet server calls the control routine with a <telnetdEvent>
  404. * parameter of REMOTE_INIT during inititialization.  The telnet server then
  405. * calls the control routine with a <telnetdEvent> parameter of REMOTE_START 
  406. * when a client establishes a new connection.
  407. * The <sessionId> parameter provides a unique identifier for the session.
  408. * In the default configuration, the telnet server calls the control routine
  409. * with a <telnetdEvent> parameter of REMOTE_STOP when a session ends. 
  410. *
  411. * The telnet server does not call the control routine when a session ends
  412. * if it is configured to spawn all tasks and allocate all resources in
  413. * advance of any connections. The associated file descriptors will be reused
  414. * by later clients and cannot be released. In that case, the REMOTE_STOP
  415. * operation only occurs to allow the command interpreter to close those
  416. * files when the server encounters a fatal error.
  417. *
  418. * VXWORKS AE PROTECTION DOMAINS
  419. * Under VxWorks AE, you can call this function from within the kernel 
  420. * protection domain only.  In addition, all arguments to this function can  
  421. * reference only that data which is valid in the kernel protection domain. 
  422. * This restriction does not apply under non-AE versions of VxWorks.  
  423. *
  424. * RETURNS: OK if parser control routine installed, or ERROR otherwise.
  425. *
  426. * INTERNAL: Can be called before or after telnetdInit() and telnetdStart()
  427. */
  428. STATUS telnetdParserSet
  429.     (
  430.     FUNCPTR     pParserCtrlRtn  /* provides parser's file descriptors */
  431.     )
  432.     {
  433.     /* We must have a valid parser */
  434.     if (pParserCtrlRtn == NULL)
  435.         return (ERROR);
  436.     /* We can not change parsers */
  437.  
  438.     if (telnetdParserControl != NULL)
  439.         return (ERROR);
  440.     /* Store the provided control routine.  */
  441.     telnetdParserControl = pParserCtrlRtn;
  442.     /* Allow client connections. */
  443.     telnetdParserFlag = TRUE; 
  444.     return (OK);
  445.     }
  446. /*******************************************************************************
  447. *
  448. * telnetdIoTasksCreate  - Create tasks to transferring i/o between socket and fd
  449. * Two tasks are created: An input task and an output task.  The name is based on
  450. *    the pSlot argument for uniqueness.
  451. *
  452. * NOMANUAL
  453. * RETURNS: OK if parser control routine installed, or ERROR otherwise.
  454. */
  455. LOCAL STATUS telnetdIoTasksCreate
  456.     (
  457.     TELNETD_SESSION_DATA *pSlot
  458.     )
  459.     {
  460.     char sessionTaskName[IO_TASK_NAME_MAX_LEN];
  461.     char sessionInTaskName[IO_TASK_NAME_MAX_LEN];
  462.     char sessionOutTaskName[IO_TASK_NAME_MAX_LEN];
  463.  
  464.     int result;
  465.     /*
  466.      * Spawn the input and output tasks which transfer data between
  467.      * the socket and the i/o file descriptor. 
  468.      *
  469.      * If created in advance (static) the task pend on a semaphore
  470.      */
  471.     sprintf (sessionTaskName, "_%x", (unsigned int)pSlot);
  472.     sprintf (sessionInTaskName, "tTelnetIn%s", sessionTaskName);
  473.     sprintf (sessionOutTaskName,"tTelnetOut%s", sessionTaskName);
  474.   
  475.     if (telnetdTaskFlag) 
  476.         {
  477.         pSlot->startOutput = semBCreate (SEM_Q_FIFO, SEM_EMPTY);
  478.         pSlot->startInput = semBCreate (SEM_Q_FIFO, SEM_EMPTY);
  479.         if ((pSlot->startInput == NULL)  || (pSlot->startInput == NULL))
  480.             {
  481.             TELNETD_DEBUG ("telnetd: Unable to create semaphore. errno:%#xn", 
  482.                            errno, 0, 0, 0, 0, 0);
  483.             result = ERROR;
  484.             return ERROR;
  485.             }
  486.         }
  487.     pSlot->outputTask = taskSpawn (sessionOutTaskName, 
  488.                                    telnetTaskPriority,
  489.                                    telnetTaskOptions, 
  490.                                    telnetTaskStackSize,
  491.                                    (FUNCPTR)telnetOutTask, 
  492.                                    (int)pSlot,
  493.                                    0, 0, 0, 0, 0, 0, 0, 0, 0);
  494.     if (pSlot->outputTask == ERROR)
  495.         {
  496.         TELNETD_DEBUG ("telnetd: Unable to create task. errno:%#xn", 
  497.                        errno, 0, 0, 0, 0, 0);
  498.         result = ERROR;
  499.         return ERROR;
  500.         }
  501.     pSlot->inputTask = taskSpawn (sessionInTaskName, 
  502.                                   telnetTaskPriority,
  503.                                   telnetTaskOptions, 
  504.                                   telnetTaskStackSize,
  505.                                   (FUNCPTR)telnetInTask, 
  506.                                   (int)pSlot,
  507.                                   0, 0, 0, 0, 0, 0, 0, 0, 0);
  508.     if (pSlot->inputTask == ERROR)
  509.         {
  510.         TELNETD_DEBUG ("telnetd: Unable to create task. errno:%#xn", 
  511.                        errno, 0, 0, 0, 0, 0);
  512.         taskDelete (pSlot->outputTask);
  513.         
  514.         result = ERROR;
  515.         return ERROR;
  516.         }
  517.     return OK;
  518.     }
  519. /*******************************************************************************
  520. *
  521. * telnetdSessionPtysCreate  - Create a pty pair and open them 
  522. * Two file descriptors are created: An input and an output fd.  The name is 
  523. *    based on the pSlot argument for uniqueness.  The file descriptors are 
  524. *    stored in the session structure.
  525. *
  526. * NOMANUAL
  527. * RETURNS: OK if successfull, or ERROR otherwise.
  528. */
  529. LOCAL STATUS telnetdSessionPtysCreate 
  530.     (
  531.     TELNETD_SESSION_DATA *pSlot
  532.     )
  533.     {
  534.     char sessionPtyRemoteName[PTY_DEVICE_NAME_MAX_LEN];
  535.     char sessionPtyRemoteNameM[PTY_DEVICE_NAME_MAX_LEN];
  536.     char sessionPtyRemoteNameS[PTY_DEVICE_NAME_MAX_LEN];
  537.     /* Create unique names for the pty device */
  538.     sprintf (sessionPtyRemoteName, "%s_%x.", ptyRemoteName, (int)pSlot);
  539.     sprintf (sessionPtyRemoteNameM, "%sM", sessionPtyRemoteName);
  540.     sprintf (sessionPtyRemoteNameS, "%sS", sessionPtyRemoteName);
  541.     /* pseudo tty device creation */
  542.     if (ptyDevCreate (sessionPtyRemoteName, 
  543.                       PTY_BUFFER_SIZE, 
  544.                       PTY_BUFFER_SIZE) == ERROR)
  545.         {
  546.         return ERROR;
  547.         }
  548.     /* Master-side open of pseudo tty */
  549.     strcpy (pSlot->ptyRemoteName, sessionPtyRemoteName);
  550.     if ((masterFd = open (sessionPtyRemoteNameM, O_RDWR, 0)) == ERROR)
  551.         {
  552.         return ERROR;
  553.         }
  554.     else
  555.         {
  556.         pSlot->inputFd = masterFd;
  557.         pSlot->outputFd = masterFd;
  558.         }
  559.     /* Slave-side open of pseudo tty */
  560.     if ((pSlot->slaveFd = open (sessionPtyRemoteNameS, O_RDWR, 0)) == ERROR)
  561.         {
  562.         return ERROR;
  563.         }
  564.     /* setup the slave device to act like a terminal */
  565.     (void) ioctl (pSlot->slaveFd, FIOOPTIONS, OPT_TERMINAL);
  566.     return OK;
  567.     }
  568. /*******************************************************************************
  569. *
  570. * telnetdStart - initialize the telnet services
  571. *
  572. * Following the telnet server initialization, this routine creates a socket
  573. * for accepting remote connections and spawns the primary telnet server task.
  574. * It executes automatically during system startup when the INCLUDE_TELNET
  575. * configuration macro is defined since a parser control routine is available.
  576. * The server will not accept connections otherwise.
  577. *
  578. * By default, the server will spawn a pair of secondary input and output
  579. * tasks after each client connection. Changing the TELNETD_TASKFLAG setting
  580. * to TRUE causes this routine to create all of those tasks in advance of
  581. * any connection. In that case, it calls the current parser control routine
  582. * repeatedly to obtain file descriptors for each possible client based on
  583. * the <numClients> argument to the initialization routine. The server will
  584. * not start if the parser control routine returns ERROR.
  585. *
  586. * The TELNETD_PORT constant provides the <port> argument, which assigns the
  587. * port where the server accepts connections. The default value is the standard
  588. * setting of 23. 
  589. *
  590. * VXWORKS AE PROTECTION DOMAINS
  591. * Under VxWorks AE, you can call this function from within the kernel 
  592. * protection domain only.  This restriction does not apply under non-AE 
  593. * versions of VxWorks.  
  594. *
  595. * RETURNS: OK, or ERROR if startup fails
  596. */
  597. STATUS telnetdStart
  598.     (
  599.     int port  /* target port for accepting connections */
  600.     )
  601.     {
  602.     struct sockaddr_in serverAddr;
  603.     if (!telnetdInitialized)
  604.         {
  605.         TELNETD_DEBUG ("telnetd: Must be initialized with telnetdInit() first.n", 
  606.                        0, 0, 0, 0, 0, 0);
  607.         return (ERROR);
  608.         }
  609.     if (telnetdStartFlag)
  610.         return (OK);
  611.     /* 
  612.      * At this point (for both static and dynamic task initialization) we 
  613.      * are ready to create the server socket.
  614.      */
  615.     telnetdServerSock = socket (AF_INET, SOCK_STREAM, 0);
  616.     if (telnetdServerSock < 0)
  617.         return (ERROR);
  618.     bzero ((char *)&serverAddr, sizeof (serverAddr));
  619.     serverAddr.sin_family = AF_INET;
  620.     serverAddr.sin_port   = htons (port);
  621.     if (bind (telnetdServerSock, (struct sockaddr *) &serverAddr,
  622.               sizeof (serverAddr)) < 0)
  623.         {
  624.         close (telnetdServerSock);
  625.         if (telnetdTaskFlag)
  626.             telnetdTaskDelete (telnetdMaxClients);
  627.         return (ERROR);
  628.         }
  629.     if (listen (telnetdServerSock, 5) < 0)
  630.         {
  631.         close (telnetdServerSock);
  632.         if (telnetdTaskFlag)
  633.             telnetdTaskDelete (telnetdMaxClients);
  634.         return (ERROR);
  635.         }
  636.       
  637.     /* Create a telnet server task to receive connection requests. */
  638.     telnetdTaskId = taskSpawn ("tTelnetd", 
  639.                                telnetTaskPriority,
  640.                                telnetTaskOptions, 
  641.                                telnetTaskStackSize,
  642.                                (FUNCPTR)telnetd, 
  643.                                0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  644.     if (telnetdTaskId == ERROR)
  645.         {
  646.         close (telnetdServerSock);
  647.         if (telnetdTaskFlag)
  648.             telnetdTaskDelete (telnetdMaxClients);
  649.         return (ERROR);
  650.         }
  651.     return (OK);
  652.     }
  653. /*******************************************************************************
  654. *
  655. * telnetdTaskDelete - remove task data from task list
  656. *
  657. * This routine releases the system objects which monitor the secondary input
  658. * and output tasks for telnet clients. The server uses this routine to clean
  659. * up the (partial) task list if an error occurs during multiple task enabled 
  660. * startup.
  661. *
  662. * RETURNS: N/A
  663. *
  664. * NOMANUAL
  665. */
  666. LOCAL void telnetdTaskDelete
  667.     (
  668.     int  numTasks  /* number of entries to remove */
  669.     )
  670.     {
  671.     int  count;
  672.     BOOL telnetdTaskFlagSave; 
  673.     telnetdTaskFlagSave = telnetdTaskFlag; /* Save original state */
  674.     /* 
  675.      * Make sure the flag is set to FALSE so we delete objects instead of
  676.      * restart objects with  telnetdSessionDisconnectFromShell ()
  677.      */
  678.     telnetdTaskFlag = FALSE;
  679.     for (count = 0; count < numTasks; count++)
  680.         {
  681.         if (telnetdParserControl != NULL)
  682.            (*telnetdParserControl) (REMOTE_STOP, 
  683.                                     telnetdTaskList [count].pSession,
  684.                                     0);  
  685.         if (telnetdTaskList [count].pSession != NULL)
  686.             {
  687.             telnetdSessionDisconnect (telnetdTaskList [count].pSession, TRUE);
  688.             free (telnetdTaskList [count].pSession);
  689.             }
  690.         }
  691.  
  692.     free (telnetdTaskList);
  693.     semDelete (telnetdMutexSem);
  694.     telnetdTaskFlag = telnetdTaskFlagSave; /* Restore original state */
  695.     return;
  696.     }
  697. /*******************************************************************************
  698. *
  699. * telnetdExit - close an active telnet session
  700. *
  701. * This routine supports the session exit command for a command interpreter
  702. * (such as logout() for the VxWorks shell). Depending on the TELNETD_TASKFLAG
  703. * setting, it causes the associated input and output tasks to restart or exit.
  704. * The <sessionId> parameter must match a value provided to the command
  705. * interpreter with the REMOTE_START option.
  706. *
  707. * INTERNAL
  708. * This routine is used for termination via the shell.  The inTask may also 
  709. *   terminate the connection via telnetdSessionDisconnectFromShell()
  710. *
  711. * RETURNS: N/A.
  712. *
  713. * ERRNO: N/A
  714. */
  715. void telnetdExit
  716.     (
  717.     UINT32 sessionId  /* identifies the session to be deleted */
  718.     )
  719.     {
  720.     telnetdSessionDisconnectFromShell ((TELNETD_SESSION_DATA *)sessionId);
  721.     return;
  722.     }
  723. /*******************************************************************************
  724. *
  725. * telnetdSessionAdd - add a new entry to the telnetd session slot list
  726. *
  727. * Each of the telnet clients is associated with an entry in the server's
  728. * session list which records the session-specific context for each
  729. * connection, including the file descriptors that access the command
  730. * interpreter. This routine creates and initializes a new entry in the
  731. * session list, unless the needed memory is not available or the upper
  732. * limit for simultaneous connections is reached.
  733. *
  734. * RETURNS: A pointer to the session list entry, or NULL if none available.
  735. *
  736. * ERRNO: N/A
  737. *
  738. * NOMANUAL
  739. *
  740. */
  741. LOCAL TELNETD_SESSION_DATA *telnetdSessionAdd (void)
  742.     {
  743.     TELNETD_SESSION_DATA *  pSlot;
  744.     int count = 0;
  745.     semTake (telnetdMutexSem, WAIT_FOREVER); 
  746.     if (telnetdCurrentClients == telnetdMaxClients)
  747.         {
  748.         semGive (telnetdMutexSem); 
  749.         return (NULL);
  750.         }
  751.     /* Find an idle pair of input/output tasks, if needed. */
  752.     if (telnetdTaskFlag)     /* Tasks created during server startup? */
  753.         {
  754.         for (count = 0; count < telnetdMaxClients; count++)
  755.             if (!telnetdTaskList [count].pSession->busyFlag)
  756.                 break;
  757.         }
  758.    
  759.     /* Are there no more sessions available ? */ 
  760.     if (telnetdTaskFlag && (count == telnetdMaxClients))
  761.         {
  762.         semGive (telnetdMutexSem); 
  763.         return ((TELNETD_SESSION_DATA *) NULL);
  764.         }
  765.   
  766.     /* get memory for the new session entry */
  767.     if (telnetdTaskFlag)     
  768.        pSlot = telnetdTaskList [count].pSession;
  769.     else 
  770.        {
  771.        pSlot = (TELNETD_SESSION_DATA *) calloc (sizeof (TELNETD_SESSION_DATA), 
  772.                1);
  773.        if (pSlot == NULL)
  774.            {
  775.            semGive (telnetdMutexSem); 
  776.            return (NULL);
  777.            }
  778.        telnetdTaskList [count].pSession = pSlot;
  779.        }
  780.     pSlot->busyFlag = TRUE;
  781.     pSlot->loggedIn = FALSE;
  782.     telnetdCurrentClients++;
  783.     if (!telnetdTaskFlag)
  784.         {
  785.         /* 
  786.          * Dynamic session creation needs all elements of the structure 
  787.          * initialized to sane values 
  788.          */
  789.         pSlot->socket         = -1;
  790.         pSlot->inputFd        = -1;            
  791.         pSlot->outputFd       = -1;          
  792.         pSlot->slaveFd        = -1;          
  793.         pSlot->outputTask     = -1;      
  794.         pSlot->inputTask      = -1;      
  795.         pSlot->parserControl  = 0; 
  796.         }
  797.     /* Add new entry to the list of active sessions. */
  798.     lstAdd (&telnetdSessionList, &pSlot->node);
  799.     semGive (telnetdMutexSem); 
  800.     return (pSlot);
  801.     }
  802. /*******************************************************************************
  803. *
  804. * telnetdSessionDisconnect - Shut down a session
  805. *
  806. * This routine removes a connection and all associated resources for it.
  807. *
  808. * This may be called because of login failure or end of a shell session
  809. *
  810. * NOMANUAL
  811. */
  812. LOCAL void telnetdSessionDisconnect 
  813.      (
  814.      TELNETD_SESSION_DATA *pSlot, 
  815.      BOOL pSlotDelete /* For DYNAMIC mode,  should pSlot be free'd when done? */
  816.      )
  817.      {
  818.      if (pSlot == NULL)
  819.          return;
  820.      semTake (telnetdMutexSem, WAIT_FOREVER); 
  821.      /* 
  822.       * Make sure the task is still valid.  It is possible that 
  823.       * the connection was killed during login (telnetInTask),
  824.       *                    failed login (telnetd)
  825.       *                    terminated by shell (shell task)
  826.       */
  827.       
  828.      /* For STATIC sessions,  we need to clean/sanitize all of it's resources */
  829.      if (telnetdTaskFlag)  
  830.         {
  831.         /* Halt the i/o tasks */
  832.         if (pSlot->outputTask)
  833.             taskSuspend (pSlot->outputTask);
  834.         if (pSlot->inputTask)
  835.             taskSuspend (pSlot->inputTask);
  836.         /* Make sure the semaphores are empty */
  837.         if (pSlot->startInput)
  838.             semTake (pSlot->startInput, NO_WAIT);
  839.         if (pSlot->startOutput)
  840.             semTake (pSlot->startOutput, NO_WAIT);
  841.         /* Restart the I/O tasks, they will pend on the empty semaphores */
  842.         if (pSlot->outputTask)
  843.             taskRestart (pSlot->outputTask);
  844.         if (pSlot->inputTask)
  845.             taskRestart (pSlot->inputTask);
  846.         /* Clear out the i/o descriptors */
  847.         if ((pSlot->outputFd) > STD_ERR)
  848.             ioctl (pSlot->outputFd, FIOFLUSH, 0);
  849.         if ((pSlot->slaveFd) > STD_ERR)
  850.             ioctl (pSlot->slaveFd, FIOFLUSH, 0);
  851.         /* Close the socket connection to the client */
  852.         if ((pSlot->socket) > STD_ERR)
  853.              close (pSlot->socket);
  854.   
  855.         /* 
  856.          * Re-Initialize some elements of the structure to sane values 
  857.          * We will not re-initialize the taskId's or the i/o file descriptors
  858.          * because these resources are just reset and not removed.
  859.          */
  860.         pSlot->socket        = -1;
  861.         pSlot->parserControl = telnetdParserControl;
  862.         pSlot->loggedIn      = FALSE;
  863.         pSlot->busyFlag      = FALSE;
  864.         --telnetdCurrentClients;
  865.         lstDelete (&telnetdSessionList, &pSlot->node);
  866.         }
  867.      else
  868.         {
  869.         /* For DYNAMIC sessions,  we need to free all of it's resources */
  870.         /* Remove the i/o tasks */
  871.         if (pSlot->outputTask)
  872.             taskDelete (pSlot->outputTask);
  873.         if (pSlot->inputTask)
  874.             taskDelete (pSlot->inputTask);
  875.         /* Delete the semaphores */
  876.         if (pSlot->startInput)
  877.             semDelete (pSlot->startInput);
  878.         if (pSlot->startOutput)
  879.             semDelete (pSlot->startOutput);
  880.         /* Close the i/o descriptors */
  881.         if ((pSlot->outputFd) > STD_ERR)
  882.             close (pSlot->outputFd);
  883.         if ((pSlot->slaveFd) > STD_ERR)
  884.             close (pSlot->slaveFd);
  885.         /* Remove the pseudo terminal for the session. */
  886.         (void) ptyDevRemove (pSlot->ptyRemoteName);
  887.         /* Close the socket connection to the client */
  888.         if ((pSlot->socket) > STD_ERR)
  889.              close (pSlot->socket);
  890.   
  891.         /* Re-Initialize all elements of the structure to sane values */
  892.         pSlot->socket         = -1;
  893.         pSlot->inputFd        = -1;            
  894.         pSlot->outputFd       = -1;          
  895.         pSlot->slaveFd        = -1;          
  896.         pSlot->outputTask     = 0;      
  897.         pSlot->inputTask      = 0;      
  898.         pSlot->parserControl  = 0; 
  899.         pSlot->busyFlag       = FALSE;
  900.         --telnetdCurrentClients;
  901.         lstDelete (&telnetdSessionList, &pSlot->node);
  902.         /* 
  903.          * If we are not logged in, then the connection must have been shut down
  904.          * during login.   When the login routine terminates, the pSlot will be
  905.          * free'd. This will be determined by the telnetd if parserControl == 0
  906.          */
  907.         if ((pSlot->loggedIn == TRUE) && 
  908.             (pSlotDelete == TRUE))
  909.             free (pSlot);
  910.         else
  911.             pSlot->loggedIn = FALSE; 
  912.         }
  913.      semGive (telnetdMutexSem); 
  914.      }
  915. /*******************************************************************************
  916. *
  917. * telnetdSessionDisconnectFromShellJob - terminate a session from the shell
  918. *
  919. * This is called from the shell context during a excTask() and is invoked 
  920. * by calling telnetdSessionDisconnectFromShell.
  921. *
  922. * NOTE: The inTask may also terminate the connection via 
  923. *       telnetdSessionDisconnectFromRemote()
  924. *
  925. * RETURNS N/A
  926. *
  927. * NOMANUAL
  928. */
  929. LOCAL void telnetdSessionDisconnectFromShellJob (TELNETD_SESSION_DATA *pSlot)
  930.     {
  931.     /* Shut down the connection */
  932.     telnetdSessionDisconnect (pSlot, FALSE);
  933.     if (*telnetdParserControl) 
  934.         (*telnetdParserControl) (REMOTE_STOP, pSlot, 0);  
  935.     if (!telnetdTaskFlag)
  936.         free (pSlot);
  937.     }
  938. /*******************************************************************************
  939. *
  940. * telnetdSessionDisconnectFromShell - terminate a session from the shell
  941. *
  942. * This is called from the shell context during a logout() call 
  943. * NOTE: The inTask may also terminate the connection via 
  944. *       telnetdSessionDisconnectFromRemote()
  945. *
  946. * RETURNS N/A
  947. *
  948. * NOMANUAL
  949. */
  950. LOCAL void telnetdSessionDisconnectFromShell (TELNETD_SESSION_DATA *pSlot)
  951.      {
  952.      excJobAdd (telnetdSessionDisconnectFromShellJob, 
  953.                 (int) pSlot, 
  954.                 0, 0, 0, 0, 0);
  955.      taskDelay (sysClkRateGet());
  956.      }
  957. /*******************************************************************************
  958. *
  959. * telnetdSessionDisconnectFromRemote - terminate a session from the shell
  960. *
  961. * This is called from the telnetInTask context if the user terminates the 
  962. * connection.
  963. *
  964. * RETURNS N/A
  965. *
  966. * NOMANUAL
  967. */
  968. LOCAL void telnetdSessionDisconnectFromRemote (TELNETD_SESSION_DATA *pSlot)
  969.     {
  970.     /* Make the shell restart locally */
  971.     (*telnetdParserControl) (REMOTE_STOP, pSlot, 0); 
  972.     /* The shell will terminate the connection for us */
  973.     if (pSlot->loggedIn == TRUE)
  974.         {
  975.         /* Shut down the connection */
  976.         telnetdSessionDisconnect (pSlot, TRUE);
  977.         }
  978.     taskDelay (sysClkRateGet()); 
  979.     }
  980. /*******************************************************************************
  981. *
  982. * telnetd - primary telnet server task
  983. *
  984. * This routine monitors the telnet port for connection requests from clients.
  985. * It is the entry point for the primary telnet task created during the
  986. * library initialization.
  987. *
  988. * The server will only accept telnet connection requests when a task is
  989. * available to handle the input and provide output to the remote user.
  990. * The default configuration uses the shell for this purpose by redirecting
  991. * the `stdin', `stdout', and `stderr' file descriptors away from the console.
  992. * When the remote user disconnects, those values are restored to their
  993. * previous settings and the shell is restarted.
  994. *
  995. * RETURNS: N/A
  996. *
  997. * NOMANUAL
  998. */
  999. void telnetd (void)
  1000.     {
  1001.     struct sockaddr_in clientAddr;
  1002.     int clientAddrLen;
  1003.     int newSock;
  1004.     int optval;
  1005.     TELNETD_SESSION_DATA *pSlot;
  1006.     BOOL startFlag;  /* Command interpreter started successfully? */
  1007.     STATUS result;
  1008.     FOREVER
  1009.         {
  1010.         clientAddrLen = sizeof (clientAddr);
  1011.         pSlot = NULL;
  1012.         result = OK;
  1013.         startFlag = FALSE;
  1014.         newSock = accept (telnetdServerSock,
  1015.                           (struct sockaddr *) &clientAddr, &clientAddrLen);
  1016.         if (newSock == ERROR)
  1017.             {
  1018.             break;     /* Exit if unable to accept connection. */
  1019.             }
  1020.         /* 
  1021.          * Get (static) or create (dynamic) a new session entry for this 
  1022.          * connection */
  1023.         pSlot = telnetdSessionAdd ();
  1024.         /* Check if the maximum number of connections has been reached. */
  1025.         if (pSlot == NULL)  
  1026.             {
  1027.             fdprintf (newSock, "rnSorry, session limit reached.rn");
  1028.             /* Prevent denial of service attack by waiting 5 seconds */
  1029.             taskDelay (sysClkRateGet () * 5);  
  1030.             close (newSock);
  1031.             result = ERROR;
  1032.             continue;
  1033.             }
  1034.         pSlot->socket = newSock;
  1035.         /* If we haven't created the pseudo tty device, so so now */
  1036.         if (remoteInitFlag == FALSE)
  1037.             {
  1038.             /* Create pty device for all remote sessions. */
  1039.             if (ptyDrv () == ERROR)
  1040.                 {
  1041.                 fdprintf (newSock, "nntelnetd: Unable to initialize ptyDrv().  errno:%#xn", 
  1042.                           errno, 0, 0, 0, 0, 0);
  1043.                 /* Prevent denial of service attack by waiting 5 seconds */
  1044.                 taskDelay (sysClkRateGet () * 5);  
  1045.                 close (newSock);
  1046.                 continue;
  1047.                 result = ERROR;
  1048.                 }
  1049.             remoteInitFlag = TRUE;   /* Disable further device creation. */
  1050.             }
  1051.         /* Check if we are in the dynamic mode */
  1052.         if (!telnetdTaskFlag)
  1053.             {
  1054.             /*
  1055.              * Create the pseudo terminal for a session. The remote machine
  1056.              * will write to the master side and read from the slave side.
  1057.              * 
  1058.              */
  1059.             result = telnetdSessionPtysCreate (pSlot);
  1060.             if (result == OK)
  1061.                 result = telnetdIoTasksCreate (pSlot);
  1062.             if (result == ERROR)
  1063.                 {
  1064.                 fdprintf (newSock, 
  1065.                           "rntelnetd: Sorry, session limit reached. Unable to spawn tasks. errno %#xrn", 
  1066.                           errno);
  1067.                 /* Prevent denial of service attack by waiting 5 seconds */
  1068.                 taskDelay (sysClkRateGet () * 5); 
  1069.                 telnetdSessionDisconnect (pSlot, TRUE);
  1070.                 result = ERROR;
  1071.                 continue;
  1072.                 }
  1073.             }
  1074.         /* setup the slave device to act like a terminal */
  1075.         (void) ioctl (pSlot->slaveFd, FIOOPTIONS, OPT_TERMINAL);
  1076.         /* Check if a parser has been installed */
  1077.         if (!telnetdParserFlag)
  1078.             {
  1079.             fdprintf (newSock, 
  1080.                       "rntelnetd: Sorry, a shell has not been installed.rn"
  1081.                      );
  1082.             /* Prevent denial of service attack by waiting 5 seconds */
  1083.             taskDelay (sysClkRateGet () * 5);  
  1084.             telnetdSessionDisconnect (pSlot, TRUE);
  1085.             continue;
  1086.             }
  1087.         /*
  1088.          * Spawn (or wake up) the input task which transfers data from
  1089.          * the client socket and the output task which transfers data to
  1090.          * the socket. 
  1091.          */
  1092.         if (telnetdTaskFlag)
  1093.             {
  1094.             semGive (pSlot->startInput);
  1095.             semGive (pSlot->startOutput);
  1096.             }
  1097.         /* turn on KEEPALIVE so if the client crashes, we'll know about it */
  1098.         optval = 1;
  1099.         setsockopt (newSock, SOL_SOCKET, SO_KEEPALIVE,
  1100.                     (char *) &optval, sizeof (optval));
  1101.         /* initialize modes and options and offer to do remote echo */
  1102.         raw = FALSE;
  1103.         echo = TRUE;
  1104.         bzero ((char *)myOpts, sizeof (myOpts));
  1105.         bzero ((char *)remOpts, sizeof (remOpts));
  1106.         (void)localDoOpt (pSlot->slaveFd, TELOPT_ECHO, TRUE, newSock, FALSE);
  1107.         /*
  1108.          * File descriptors are available. Save the corresponding
  1109.          * parser control routine.
  1110.          */
  1111.         pSlot->parserControl = telnetdParserControl;
  1112.         /*
  1113.          * Tell the parser control function to activate the shell 
  1114.          *  for this session.
  1115.          */
  1116.         result = (*telnetdParserControl) (REMOTE_START, 
  1117.                                           (UINT32)pSlot,
  1118.                                           pSlot->slaveFd);
  1119.         /* 
  1120.          * If parserControl == 0, then the connection was terminated
  1121.          *  during login.  The inTask has already cleaned up all resources
  1122.          *  for us except the memory for pSlot.
  1123.          */
  1124.         if (pSlot->parserControl == 0)
  1125.             {
  1126.             if (!telnetdTaskFlag)
  1127.                 free (pSlot);
  1128.             continue;
  1129.             }
  1130.         /* 
  1131.          * Was the REMOTE_START of the shell successful? 
  1132.          * Did we fail the login or did the remote user disconnect?
  1133.          */ 
  1134.         if (result == ERROR) /* No,  must have failed to login */
  1135.             {
  1136.             telnetdSessionDisconnect (pSlot, TRUE);
  1137.             continue;
  1138.             }
  1139.         else  
  1140.             {
  1141.             /* 
  1142.              * We must keep track of a successfull login with 
  1143.              * 'loggedIn' element since failure to login means that the 
  1144.              * shell was not spawned.
  1145.              *
  1146.              * Future session cleanup's will know that the login has been 
  1147.              * a success.  Therefore, the parser control will need a 
  1148.              * REMOTE_STOP if the connection is ever broken.
  1149.              */
  1150.             pSlot->loggedIn = TRUE; 
  1151.             }
  1152.         }
  1153.     }
  1154. /*******************************************************************************
  1155. *
  1156. * telnetOutTask - relay output to remote user
  1157. *
  1158. * This routine transfers data from the registered input/output task to
  1159. * the remote user. It is the entry point for the output task which is
  1160. * deleted when the client disconnects.
  1161. *
  1162. * INTERNAL
  1163. * This routine blocks within the read() call until the command interpreter
  1164. * sends a response. When the telnet server creates all input/output tasks
  1165. * during startup (i.e. telnetdTaskFlag is TRUE), this routine cannot send
  1166. * any data to the socket until the primary server task (telnetd) awakens 
  1167. * the input routine.
  1168. *
  1169. * NOMANUAL
  1170. * but not LOCAL for i()
  1171. */
  1172. void telnetOutTask
  1173.     (
  1174.     TELNETD_SESSION_DATA *pSlot  /* pointer to the connection information */
  1175.     )
  1176.     {
  1177.     FAST int n;
  1178.     char buf [STDOUT_BUF_SIZE];
  1179.     int sock;     /* Socket for individual telnet session */
  1180.     int outputFd; /* Output from command interpreter */
  1181.     /*
  1182.      * Wait for a connection if the server creates this task in advance. 
  1183.      */
  1184.     if (telnetdTaskFlag)  /* static task creation  */
  1185.         semTake (pSlot->startOutput, WAIT_FOREVER);
  1186.     sock = pSlot->socket;
  1187.     outputFd = pSlot->outputFd;
  1188.     /*
  1189.      * In the default configuration, the following read loop exits after
  1190.      * the connection between the client and server ends because closing
  1191.      * the socket to the remote client causes the input task to close the
  1192.      * output file descriptor.
  1193.      *
  1194.      * When the server creates the input and output tasks in advance, that
  1195.      * operation does not occur. To prevent writing to a non-existent
  1196.      * socket, the input task restarts the output task after using the
  1197.      * FIOFLUSH ioctl to prevent stale data from reaching the next session.
  1198.      */
  1199.     while ((n = read (outputFd, buf, sizeof (buf))) > 0)
  1200.         {
  1201.         /* XXX should scan for IAC and double 'em to escape 'em */
  1202.         write (sock, buf, n);
  1203.         }
  1204.     return; /* This point is never reached */
  1205.     }
  1206. /*******************************************************************************
  1207. *
  1208. * telnetInTask - relay input from remote user
  1209. *
  1210. * This routine transfers data from the remote user to the registered
  1211. * input/output task. It is deleted when the client disconnects. The
  1212. * <slot> argument has two possible meanings. In the default setup,
  1213. * it provides access to the session data which includes two file
  1214. * descriptors: one for a socket (to the remote client) and another
  1215. * provided by the command interpreter for the connection. That
  1216. * information is not available when the server creates the input/output
  1217. * tasks in advance. 
  1218. *
  1219. * RETURNS: N/A.
  1220. *
  1221. * NOMANUAL
  1222. * but not LOCAL for i()
  1223. */
  1224. void telnetInTask
  1225.     (
  1226.     TELNETD_SESSION_DATA * pSlot
  1227.     )
  1228.     {
  1229.     int n;
  1230.     int state = TS_DATA;
  1231.     char buf [STDIN_BUF_SIZE];
  1232.     int sock;    /* Socket for individual telnet session */
  1233.     int inputFd; /* Input to command interpreter */
  1234.     int slaveFd; /* Command interpreter stdin */
  1235.     FOREVER
  1236.         {
  1237.         /* Wait for a connection if the server creates this task in advance. */
  1238.         if (telnetdTaskFlag)  /* static creation */
  1239.             semTake (pSlot->startInput, WAIT_FOREVER);
  1240.         /*
  1241.          * Transfer data from the socket to the command interpreter, after
  1242.          * filtering out the telnet commands and options.
  1243.          */
  1244.         sock = pSlot->socket;
  1245.         inputFd = pSlot->inputFd;
  1246.         slaveFd = pSlot->slaveFd;
  1247.         while ((n = read (sock, buf, sizeof (buf))) > 0)
  1248.             state = tnInput (state, slaveFd, sock, inputFd, buf, n);
  1249.         /*
  1250.          * Terminate the session.  This is done as a seperate job because 
  1251.          *  the function telnetdSessionDisconnectFromRemote() deletes 
  1252.          *  the inTask before completion and that is our context (in this case)!
  1253.          */
  1254.         excJobAdd (telnetdSessionDisconnectFromRemote, 
  1255.                    (int)pSlot, 
  1256.                    0, 0, 0, 0, 0);
  1257.         taskSuspend (0); /* Wait to be deleted by telnetdSessionDisconnect */
  1258.         }
  1259.     return;
  1260.     }
  1261. /*******************************************************************************
  1262. *
  1263. * tnInput - process input from remote user
  1264. *
  1265. * This routine transfers input data from a telnet client's <clientSock>
  1266. * socket to the command interpreter through the <inputFd> file descriptor.
  1267. * The <state> parameter triggers interpretation of the input as raw data or
  1268. * as part of a command sequence or telnet option.
  1269. *
  1270. * RETURNS: state value for next data bytes
  1271. *
  1272. * NOMANUAL
  1273. */
  1274. LOCAL int tnInput
  1275.     (
  1276.     FAST int state,         /* state of telnet session's input handler */
  1277.     FAST int slaveFd,       /* local fd, some options adjust it via ioctl */
  1278.     FAST int clientSock,    /* socket connected to telnet client */
  1279.     FAST int inputFd,       /* input to command interpreter */
  1280.     FAST char *buf,         /* buffer containing client data */
  1281.     FAST int n              /* amount of client data in buffer */
  1282.     )
  1283.     {
  1284.     char cc;
  1285.     int ci;
  1286.     while (--n >= 0)
  1287.     {
  1288.         cc = *buf++;               /* get next character */
  1289.         ci = (unsigned char) cc;   /* convert to int since many values
  1290.                                     * are negative characters */
  1291.     switch (state)
  1292.         {
  1293.         case TS_CR:  /* doing crmod; ignore add'l linefeed */
  1294. state = TS_DATA;
  1295. if ((cc != EOS) && (cc != 'n'))
  1296.     write (inputFd, &cc, 1); /* forward char */
  1297. break;
  1298. case TS_DATA: /* just pass data */
  1299. if (ci == IAC)
  1300.     state = TS_IAC;
  1301. else
  1302.     {
  1303.     write (inputFd, &cc, 1); /* forward char */
  1304.     if (!myOpts [TELOPT_BINARY] && (cc == 'r'))
  1305. state = TS_CR;
  1306.     }
  1307. break;
  1308.     case TS_IAC:
  1309. switch (ci)
  1310.     {
  1311.     case BREAK: /* interrupt from remote */
  1312.     case IP:
  1313. /* XXX interrupt (); */
  1314. state = TS_DATA;
  1315. break;
  1316.     case AYT: /* Are You There? */
  1317. {
  1318. static char aytAnswer [] = "rn[yes]rn";
  1319. write (clientSock, aytAnswer, sizeof (aytAnswer) - 1);
  1320. state = TS_DATA;
  1321. break;
  1322. }
  1323.     case EC: /* erase character */
  1324. write (inputFd, "b", 1);
  1325. state = TS_DATA;
  1326. break;
  1327.     case EL: /* erase line */
  1328. write (inputFd, "25", 1);
  1329. state = TS_DATA;
  1330. break;
  1331.     case DM: /* data mark */
  1332. state = TS_DATA;
  1333. break;
  1334.     case SB: /* sub-option negotiation begin */
  1335. state = TS_BEGINNEG;
  1336. break;
  1337.     case WILL: state = TS_WILL; break; /* remote will do opt */
  1338.     case WONT: state = TS_WONT; break; /* remote wont do opt */
  1339.     case DO:   state = TS_DO; break; /* req we do opt */
  1340.     case DONT: state = TS_DONT; break; /* req we dont do opt */
  1341.     case IAC:
  1342. write (inputFd, &cc, 1); /* forward char */
  1343. state = TS_DATA;
  1344. break;
  1345.     }
  1346. break;
  1347.     case TS_BEGINNEG:
  1348. /* ignore sub-option stuff for now */
  1349. if (ci == IAC)
  1350.     state = TS_ENDNEG;
  1351. break;
  1352.     case TS_ENDNEG:
  1353. state = (ci == SE) ? TS_DATA : TS_BEGINNEG;
  1354. break;
  1355.     case TS_WILL: /* remote side said it will do opt */
  1356. (void)remDoOpt (slaveFd, ci, TRUE, clientSock, TRUE);
  1357. state = TS_DATA;
  1358. break;
  1359.     case TS_WONT: /* remote side said it wont do opt */
  1360. (void)remDoOpt (slaveFd, ci, FALSE, clientSock, TRUE);
  1361. state = TS_DATA;
  1362. break;
  1363.     case TS_DO: /* remote wants us to do opt */
  1364. (void)localDoOpt (slaveFd, ci, TRUE, clientSock, TRUE);
  1365. state = TS_DATA;
  1366. break;
  1367.     case TS_DONT: /* remote wants us to not do opt */
  1368. (void)localDoOpt (slaveFd, ci, FALSE, clientSock, TRUE);
  1369. state = TS_DATA;
  1370. break;
  1371.     default:
  1372. TELNETD_DEBUG ("telnetd: invalid state = %dn", state, 
  1373.                                1, 2, 3, 4, 5);
  1374. break;
  1375.     }
  1376. }
  1377.     return (state);
  1378.     }
  1379. /*******************************************************************************
  1380. *
  1381. * remDoOpt - request/acknowledge remote enable/disable of option
  1382. *
  1383. * This routine will try to accept the remote's enable or disable,
  1384. * as specified by "will", of the remote's support for the specified option.
  1385. * If the request is to disable the option, the option will always be disabled.
  1386. * If the request is to enable the option, the option will be enabled, IF we
  1387. * are capable of supporting it.  The remote is notified to DO/DONT support
  1388. * the option.
  1389. *
  1390. * RETURNS: OK or ERROR.
  1391. */
  1392. LOCAL STATUS remDoOpt
  1393.     (
  1394.     FAST int slaveFd,/* slave fd */
  1395.     FAST int opt,    /* option to be enabled/disabled */
  1396.     BOOL enable,     /* TRUE = enable option, FALSE = disable */
  1397.     int clientSock,  /* socket connection to telnet client */
  1398.     BOOL remFlag     /* TRUE = request is from remote */
  1399.     )
  1400.     {
  1401.     BOOL doOpt = enable;
  1402.     if (remOpts [opt] == enable)
  1403. return (OK);
  1404.     switch (opt)
  1405. {
  1406. case TELOPT_BINARY:
  1407. case TELOPT_ECHO:
  1408.     setMode (slaveFd, opt, enable);
  1409.     break;
  1410. case TELOPT_SGA:
  1411.     break;
  1412. default:
  1413.     doOpt = FALSE;
  1414.     break;
  1415. }
  1416.     if ((remOpts [opt] != doOpt) || remFlag)
  1417. {
  1418. char msg[3];
  1419. msg[0] = IAC;
  1420. msg[1] = doOpt ? DO : DONT;
  1421. msg[2] = opt;
  1422. write (clientSock, msg, 3);
  1423. remOpts [opt] = doOpt;
  1424. }
  1425.     return ((enable == doOpt) ? OK : ERROR);
  1426.     }
  1427. /*******************************************************************************
  1428. *
  1429. * localDoOpt - offer/acknowledge local support of option
  1430. *
  1431. * This routine will try to enable or disable local support for the specified
  1432. * option.  If local support of the option is already in the desired mode, no
  1433. * action is taken.  If the request is to disable the option, the option will
  1434. * always be disabled.  If the request is to enable the option, the option
  1435. * will be enabled, IF we are capable of supporting it.  The remote is
  1436. * notified that we WILL/WONT support the option.
  1437. *
  1438. * NOMANUAL
  1439. *
  1440. * RETURNS: OK or ERROR.
  1441. */
  1442. LOCAL STATUS localDoOpt
  1443.     (
  1444.     FAST int slaveFd,     /* slave fd */
  1445.     FAST int opt,    /* option to be enabled/disabled */
  1446.     BOOL enable,        /* TRUE = enable option, FALSE = disable */
  1447.     int clientSock,     /* socket connection to telnet client */
  1448.     BOOL remFlag     /* TRUE = request is from remote */
  1449.     )
  1450.     {
  1451.     BOOL will = enable;
  1452.     if (myOpts [opt] == enable)
  1453. return (OK);
  1454.     switch (opt)
  1455. {
  1456. case TELOPT_BINARY:
  1457. case TELOPT_ECHO:
  1458.     setMode (slaveFd, opt, enable);
  1459.     break;
  1460. case TELOPT_SGA:
  1461.     break;
  1462. default:
  1463.     will = FALSE;
  1464.     break;
  1465. }
  1466.     if ((myOpts [opt] != will) || remFlag)
  1467. {
  1468. char msg[3];
  1469. msg[0] = IAC;
  1470. msg[1] = will ? WILL : WONT;
  1471. msg[2] = opt;
  1472. write (clientSock, msg, 3);
  1473. myOpts [opt] = will;
  1474. }
  1475.     return ((will == enable) ? OK : ERROR);
  1476.     }
  1477. /*******************************************************************************
  1478. *
  1479. * setMode - set telnet option
  1480. *
  1481. * RETURNS: N/A.
  1482. *
  1483. * NOMANUAL
  1484. *
  1485. */
  1486. LOCAL void setMode
  1487.     (
  1488.     int fd,
  1489.     int telnetOption,
  1490.     BOOL enable
  1491.     )
  1492.     {
  1493.     FAST int ioOptions;
  1494.     switch (telnetOption)
  1495.         {
  1496.         case TELOPT_BINARY: raw  = enable; break;
  1497.         case TELOPT_ECHO:   echo = enable; break;
  1498.         }
  1499.     if (raw)
  1500.         ioOptions = 0;
  1501.     else
  1502.         {
  1503.         ioOptions = OPT_7_BIT | OPT_ABORT | OPT_TANDEM | OPT_LINE;
  1504.         if (echo)
  1505.             {
  1506.             ioOptions |= (OPT_ECHO | OPT_CRMOD);
  1507.             }
  1508.     }
  1509.     (void) ioctl (fd, FIOOPTIONS, ioOptions);
  1510.     }
  1511. /*******************************************************************************
  1512. *
  1513. * telnetdStaticTaskInitializationGet - report whether tasks were pre-started by telnetd
  1514. *
  1515. * This function is called by a custom shell parser library to determine if a shell 
  1516. * is to be spawned at the time a connection is requested.
  1517. *
  1518. * RETURNS  
  1519. *
  1520. * TRUE, if all tasks are pre-spawned; FALSE, if tasks are spawned at the 
  1521. * time a connection is requested.
  1522. *
  1523. * SEE ALSO: telnetdInit(), telnetdParserSet()
  1524. *
  1525. * INTERNAL
  1526. * This routine is used by custom shells and is demonstrated in the 
  1527. * unsupported user shell echoShell.c
  1528. *
  1529. */
  1530. BOOL telnetdStaticTaskInitializationGet()
  1531.     {
  1532.     return (telnetdTaskFlag);
  1533.     }