home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / k95source / iksdsvc.c < prev    next >
C/C++ Source or Header  |  2020-01-01  |  30KB  |  978 lines

  1. /* Windows Internet Kermit Service Daemon (WIKSD):
  2.  * Copyright (C) 1985, 2003, Trustees of Columbia University in the City of New
  3.  * York.  All rights reserved.
  4.  *  
  5.  * PERMISSIONS:
  6.  *  
  7.  *   The WIKSD software may be obtained directly, in binary form only, from
  8.  *   the Kermit Project at Columbia University by any individual for his or
  9.  *   her OWN USE, and by any company or other organization for its own
  10.  *   INTERNAL DISTRIBUTION and use, including installation on servers that
  11.  *   are accessed by customers or clients, WITHOUT EXPLICIT LICENSE.  All
  12.  *   other forms of redistribution must be licensed from the Kermit Project
  13.  *   at Columbia University.  These permissions apply only to the nonsecure
  14.  *   version of WIKSD.
  15.  *  
  16.  * DISCLAIMER:
  17.  *  
  18.  *   THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE
  19.  *   TRUSTEES OF COLUMBIA UNIVERSITY IN THE CITY OF NEW YORK AS TO ITS
  20.  *   FITNESS FOR ANY PURPOSE, AND WITHOUT WARRANTY BY THE TRUSTEES OF
  21.  *   COLUMBIA UNIVERSITY IN THE CITY OF NEW YORK OF ANY KIND, EITHER
  22.  *   EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
  23.  *   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  24.  *   THE TRUSTEES OF COLUMBIA UNIVERSITY IN THE CITY OF NEW YORK SHALL NOT
  25.  *   BE LIABLE FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL,
  26.  *   OR CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING OUT OR IN
  27.  *   CONNECTION WITH THE USE OF THE SOFTWARE, EVEN IF IT HAS BEEN OR IS
  28.  *   HEREAFTER ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.  YOU SHALL
  29.  *   INDEMNIFY AND HOLD HARMLESS THE TRUSTEES OF COLUMBIA UNIVERSITY IN
  30.  *   THE CITY OF NEW YORK, ITS EMPLOYEES AND AGENTS FROM AND AGAINST ANY
  31.  *   AND ALL CLAIMS, DEMANDS, LOSS, DAMAGE OR EXPENSE (INCLUDING
  32.  *   ATTORNEYS' FEES) ARISING OUT OF YOUR USE OF THIS SOFTWARE.
  33.  *  
  34.  * The above copyright notice, permissions notice, and disclaimer may not be
  35.  * removed, altered, or obscured and shall be included in all copies of the
  36.  * WIKSD software.  The Trustees of Columbia University in the City of
  37.  * New York reserve the right to revoke this permission if any of the terms
  38.  * of use set forth above are breached.
  39.  *  
  40.  * For further information, contact the Kermit Project, Columbia University,
  41.  * 612 West 115th Street, New York NY 10025-7799, USA; Phone +1 (212) 854 3703,
  42.  * Fax +1 (212) 662 6442, kermit@columbia.edu, http://www.columbia.edu/kermit/
  43.  */
  44.  
  45. /* On Windows compile with the command line:
  46.  *  
  47.  *  cl /MT -DNT iksdsvc.c wsock32.lib advapi32.lib
  48.  */
  49.  
  50. /* 
  51.  * Data for the Windows Service IKSDSVC could be stored in:
  52.  * 
  53.  *   HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\IKSD\
  54.  */
  55.  
  56. #include <stdio.h>
  57.  
  58. #ifdef NT
  59. #include <windows.h>
  60. #include <winsock.h>
  61. #include <winsvc.h>
  62. #include <process.h>
  63. #define strdup _strdup
  64. #define ltoa   _ltoa
  65. #endif
  66. #define CONFIG_FILE "iksd.cfg"
  67.  
  68. #define bzero(x,y) memset(x,0,y)
  69. #define BSDSELECT
  70.  
  71. #define MAXPORTS 32
  72. struct PORT
  73. {
  74.     short id ;
  75.     int   lsocket ;
  76.     int   asocket ;
  77.     char  * k95cmd ;
  78.     int   showcmd;
  79. } ports[MAXPORTS] ;
  80. int portcount = 0 ;
  81.  
  82. #define MAXCHILDREN 4096
  83. struct CHILDREN
  84. {
  85.     HANDLE hProcess;
  86.     int    socket;
  87. } children[MAXCHILDREN];
  88. int childcount = 0;
  89.  
  90. SERVICE_STATUS          IKSDStatus;
  91. SERVICE_STATUS_HANDLE   IKSDStatusHandle;
  92. int iksd_started = 0;
  93. int ready_to_accept = 0 ;
  94. static struct servent *service, servrec;
  95. static struct hostent *host;
  96. static struct sockaddr_in saddr;
  97. static int saddrlen ;
  98. #ifdef BSDSELECT
  99. fd_set rfds;
  100. struct timeval tv;
  101. #endif /* BSDSELECT */
  102. int tcpsrv_fd = -1, ttyfd = -1 ;
  103.  
  104. void  WINAPI IKSDStart (DWORD argc, LPTSTR *argv);
  105. void  WINAPI IKSDCtrlHandler (DWORD opcode);
  106. DWORD IKSDInitialization (DWORD argc, LPTSTR *argv, DWORD *specificError);
  107. HANDLE StartKermit( int socket, char * cmdline, int ShowCmd, int * );
  108.  
  109. void
  110. SvcDebugOut(LPSTR String, DWORD Status)
  111. {
  112. #ifdef DEBUG
  113.     CHAR  Buffer[1024];
  114.     if (strlen(String) < 1024)
  115.     {
  116.         sprintf(Buffer, String, Status);
  117.         OutputDebugStringA(Buffer);
  118.     }
  119. #endif /* DEBUG */
  120. }
  121.  
  122. static SERVICE_TABLE_ENTRY   DispatchTable[] =
  123. {
  124.     { "IKSD", (LPSERVICE_MAIN_FUNCTION) IKSDStart },
  125.     { NULL,   NULL      }
  126. };
  127.  
  128. void
  129. init_children(void)
  130. {       
  131.     int i;
  132.     for ( i=0 ;i<MAXCHILDREN;i++ ) {
  133.         children[i].hProcess = INVALID_HANDLE_VALUE;
  134.         children[i].socket = (int)INVALID_HANDLE_VALUE;
  135.     }   
  136. }
  137.  
  138. void
  139. kill_children(void)
  140. {
  141.     int i;
  142.  
  143.     for (i=0; i<MAXCHILDREN && childcount; i++) {
  144.         if ( children[i].hProcess != INVALID_HANDLE_VALUE ) {
  145.             SvcDebugOut("TerminateProcess  %d\n",(int)children[i].hProcess);
  146.             TerminateProcess(children[i].hProcess, 1111);
  147.             closesocket(children[i].socket);
  148.             CloseHandle(children[i].hProcess);
  149.             children[i].socket = (int)INVALID_HANDLE_VALUE;
  150.             children[i].hProcess = INVALID_HANDLE_VALUE;
  151.             childcount--;       
  152.         }
  153.     }
  154. }
  155.  
  156. void
  157. check_children(void)
  158. {
  159.     int i,found;
  160.     DWORD dwExit;
  161.  
  162.     for (i=0, found=0; i<MAXCHILDREN && found<childcount; i++) {
  163.         if ( children[i].hProcess != INVALID_HANDLE_VALUE ) {
  164.             if (GetExitCodeProcess(children[i].hProcess, &dwExit)) {
  165.                 SvcDebugOut("GetExitCodeProcess ExitCode = %d\n",dwExit);
  166.                 if ( dwExit != STILL_ACTIVE ) {
  167.                     SvcDebugOut("Closing socket and process handle\n",0);
  168.                     closesocket(children[i].socket);
  169.                     CloseHandle(children[i].hProcess);
  170.                     children[i].socket = (int)INVALID_HANDLE_VALUE;
  171.                     children[i].hProcess = INVALID_HANDLE_VALUE;
  172.                     childcount--;       
  173.                     /* Do not increase found if we reduce childcount */
  174.                     continue;
  175.                 }
  176.             }
  177.             found++;
  178.         }
  179.     }
  180. }
  181.  
  182. void
  183. add_child(HANDLE hProcess, int socket)
  184. {
  185.     int i;
  186.  
  187.     while (childcount == MAXCHILDREN) {
  188.         SvcDebugOut("Max Number of Children: Going to Sleep\n",0);
  189.         Sleep(1000);
  190.         check_children();
  191.     }
  192.     
  193.     for ( i=0;i<MAXCHILDREN;i++ ) {
  194.         if ( children[i].hProcess == INVALID_HANDLE_VALUE ) {
  195.             SvcDebugOut("Child Added at %d\n",i);
  196.             children[i].hProcess = hProcess;
  197.             children[i].socket = socket;
  198.             childcount++;
  199.             return;
  200.         }
  201.     }
  202. }
  203.  
  204. int
  205. main(int argc, char **argv)
  206. {
  207.     init_children();
  208.  
  209.     if ( ParseStandardArgs(argc, argv) )
  210.         return(0);
  211.  
  212.     if (!StartServiceCtrlDispatcher(DispatchTable)) {
  213.             SvcDebugOut(" [IKSD] StartServiceCtrlDispatcher error = %d\n",
  214.                          GetLastError());
  215.             return(1);
  216.     }
  217.     return(0);
  218. }
  219.  
  220. void
  221. iksd_stopped()
  222. {
  223.     DWORD status;
  224.  
  225.     iksd_started = 0;
  226.     // Initialization complete - report running status.
  227.     IKSDStatus.dwCurrentState       = SERVICE_STOPPED;
  228.     IKSDStatus.dwCheckPoint         = 0;
  229.     IKSDStatus.dwWaitHint           = 0;
  230.  
  231.     if (!SetServiceStatus (IKSDStatusHandle, &IKSDStatus))
  232.     {
  233.         status = GetLastError();
  234.         SvcDebugOut(" [IKSD] SetServiceStatus error %ld\n",status);
  235.     }
  236.  
  237.     exit(1);
  238. }
  239.  
  240. int
  241. open_sockets(DWORD *specificError)
  242. {
  243.     int i;
  244.     int on = 1;
  245.  
  246.     for ( i=0; i<portcount; i++)
  247.     {
  248.         /* Set up socket structure and get host address */
  249.  
  250.         bzero((char *)&saddr, sizeof(saddr));
  251.         saddr.sin_family = AF_INET ;
  252.         saddr.sin_addr.s_addr = INADDR_ANY ;
  253.  
  254.         /* Get a file descriptor for the connection. */
  255.  
  256.         saddr.sin_port = ports[i].id;
  257.  
  258.         if ((ports[i].lsocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
  259.         {
  260.             perror("TCP socket error");
  261.             *specificError = 3;
  262.             return 1;
  263.         }
  264.         errno = 0;
  265.  
  266.         /* Specify the Port may be reused */
  267.         setsockopt(ports[i].lsocket, SOL_SOCKET, SO_REUSEADDR,(char *) &on, sizeof on);
  268.  
  269.         /* Now bind to the socket */
  270. #ifdef DEBUG
  271.         SvcDebugOut("Binding socket to port %d ...\n",
  272.                 ntohs((unsigned short)ports[i].id)) ;
  273. #endif
  274.         if (bind(ports[i].lsocket, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
  275.         {
  276.             i = errno;                  /* save error code */
  277.             closesocket(ports[i].lsocket) ;
  278.             ports[i].lsocket = -1 ;
  279.             ports[i].asocket = -1;
  280.             errno = i;                  /* and report this error */
  281.             SvcDebugOut("tcpsrv_open bind errno %d\n",errno);
  282.             *specificError = 4;
  283.             return 1;
  284.         }
  285. #ifdef DEBUG
  286.         SvcDebugOut("Listening ...\n",0);
  287. #endif
  288.         if (listen(ports[i].lsocket, 15) < 0)
  289.         {
  290.             i = errno;                  /* save error code */
  291.             closesocket(ports[i].lsocket) ;
  292.             ports[i].lsocket = -1 ;
  293.             ports[i].asocket = -1;
  294.             errno = i;                  /* and report this error */
  295.             SvcDebugOut("tcpsrv_open listen errno %d\n",errno);
  296.             *specificError = 5;
  297.             return 1;
  298.         }
  299.     }
  300.     return(0);
  301. }
  302.  
  303. void
  304. listen_thread( void * dummy )
  305. {
  306.     int i, j;
  307.     int on = 1;
  308.     HANDLE hProcess;
  309.     int sockdup;
  310.  
  311.     SvcDebugOut("Servicing ports:\n",0);
  312.     for ( i=0;i<portcount ;i++ )
  313.     {
  314.         SvcDebugOut("  %d\n", ntohs((unsigned short)ports[i].id) ) ;
  315.     }
  316.  
  317.     saddrlen = sizeof(saddr) ;
  318.  
  319. #ifdef BSDSELECT
  320.     tv.tv_sec  = 1L;
  321.     tv.tv_usec = 0L;
  322. #endif /* BSDSELECT */
  323.  
  324.     while ( iksd_started )
  325.     {
  326.         while ( !ready_to_accept && iksd_started )
  327.         {
  328.             check_children();
  329.  
  330. #ifdef BSDSELECT
  331.             FD_ZERO(&rfds);
  332.             for ( i=0; i<portcount;i++ )
  333.                 FD_SET(ports[i].lsocket, &rfds);
  334.             if (select(FD_SETSIZE, &rfds, NULL, NULL, &tv ) > 0)
  335.             {
  336.                 for ( i=0; i<portcount ; i++ )
  337.                 {
  338.                     if ( ready_to_accept = FD_ISSET(ports[i].lsocket, &rfds) )
  339.                         break;
  340.                 }
  341.             }
  342. #else /* BSDSELECT */
  343. #ifdef IBMSELECT
  344. ???          /* in order to make this work, we need to create an array of socket values */
  345.              ready_to_accept = (( select(&tcpsrv_fd, 1, 0, 0,1 )) == 1) ;
  346. #endif /* IBMSELECT */
  347. #endif /* BSDSELECT */
  348.         }
  349.  
  350.         if ( ready_to_accept )
  351.         {
  352.             if ((ports[i].asocket = accept(ports[i].lsocket, (struct sockaddr *)&saddr,&saddrlen)) < 0)
  353.             {
  354.                 i = errno;                      /* save error code */
  355.                 closesocket(ports[i].lsocket) ;
  356.                 ports[i].asocket = -1;
  357.                 ports[i].lsocket = -1 ;
  358.                 errno = i;                      /* and report this error */
  359.                 SvcDebugOut("tcpsrv_open accept errno %d\n",errno);
  360.                 iksd_stopped();
  361.                 return;
  362.             }
  363.  
  364.             setsockopt(ports[i].asocket, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
  365.  
  366.             if ((host = gethostbyaddr((char *)&saddr.sin_addr,4,PF_INET)) != NULL)
  367.             {
  368.                 SvcDebugOut(host->h_name,0);
  369.                 SvcDebugOut(" connected on port %d\n",ntohs(ports[i].id)) ;
  370.             }
  371.  
  372.             /* Now start subprocess */
  373.             if ( ports[i].asocket && ports[i].k95cmd ) {
  374.                 SvcDebugOut("Starting IKSD with socket %d and command\n  ",ports[i].asocket);
  375.                 SvcDebugOut(ports[i].k95cmd,0);
  376.                 SvcDebugOut("\n",0);
  377.             } else
  378.                 SvcDebugOut("Starting IKSD with socket %d\n",ports[i].asocket);
  379.             hProcess = StartKermit(ports[i].asocket,ports[i].k95cmd, ports[i].showcmd, &sockdup);
  380.             if ( hProcess != INVALID_HANDLE_VALUE ) 
  381.                 add_child(hProcess, sockdup);
  382.             else /* we used CLOSE_SOURCE when duplicating */
  383.                 closesocket(ports[i].asocket);      
  384.             ready_to_accept = 0;
  385.             continue;                           /* Go get the next one */
  386.         }
  387.         else
  388.         {
  389.             j = errno;                  /* save error code */
  390.  
  391.             if ( !iksd_started ) {
  392.                 /* Close all ports */
  393.                 for ( i=0;i<portcount;i++ ) {
  394.                     closesocket(ports[i].lsocket) ;
  395.                     ports[i].lsocket = -1;
  396.                     ports[i].asocket = -1;
  397.                 }
  398.                 iksd_stopped();
  399.             } else {
  400.                 closesocket(ports[i].lsocket) ;
  401.                 ports[i].lsocket = -1;
  402.                 ports[i].asocket = -1;
  403.             }
  404.             errno = j;                  /* and report this error */
  405.             SvcDebugOut("tcpsrv_open accept errno %d\n",errno);
  406.             return;
  407.         }
  408.     }
  409. }
  410.  
  411. void WINAPI
  412. IKSDStart (DWORD argc, LPTSTR *argv)
  413. {
  414.     DWORD status;
  415.     DWORD specificError;
  416.  
  417.     IKSDStatus.dwServiceType        = SERVICE_WIN32;
  418.     IKSDStatus.dwCurrentState       = SERVICE_START_PENDING;
  419.     IKSDStatus.dwControlsAccepted   = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE;
  420.     IKSDStatus.dwWin32ExitCode      = 0;
  421.     IKSDStatus.dwServiceSpecificExitCode = 0;
  422.     IKSDStatus.dwCheckPoint         = 0;
  423.     IKSDStatus.dwWaitHint           = 0;
  424.  
  425.     IKSDStatusHandle = RegisterServiceCtrlHandler( "IKSD", IKSDCtrlHandler);
  426.  
  427.     if (IKSDStatusHandle == (SERVICE_STATUS_HANDLE)0)
  428.     {
  429.         SvcDebugOut(" [IKSD] RegisterServiceCtrlHandler failed %d\n",
  430.                      GetLastError());
  431.         return;
  432.     }
  433.  
  434.     // Initialization code goes here.
  435.     status = IKSDInitialization(argc,argv, &specificError);
  436.  
  437.     // Handle error condition
  438.     if (status != NO_ERROR)
  439.     {
  440.         IKSDStatus.dwCurrentState       = SERVICE_STOPPED;
  441.         IKSDStatus.dwCheckPoint         = 0;
  442.         IKSDStatus.dwWaitHint           = 0;
  443.         IKSDStatus.dwWin32ExitCode      = status;
  444.         IKSDStatus.dwServiceSpecificExitCode = specificError;
  445.  
  446.         SetServiceStatus (IKSDStatusHandle, &IKSDStatus);
  447.         return;
  448.     }
  449.  
  450.     iksd_started = 1;
  451.     _beginthread(listen_thread,65536, 0);
  452.  
  453.     // Initialization complete - report running status.
  454.     IKSDStatus.dwCurrentState       = SERVICE_RUNNING;
  455.     IKSDStatus.dwCheckPoint         = 0;
  456.     IKSDStatus.dwWaitHint           = 0;
  457.  
  458.     if (!SetServiceStatus (IKSDStatusHandle, &IKSDStatus))
  459.     {
  460.         status = GetLastError();
  461.         SvcDebugOut(" [IKSD] SetServiceStatus error %ld\n",status);
  462.     }
  463.  
  464.     // This is where the service does its work.
  465.     SvcDebugOut(" [IKSD] Returning the Main Thread \n",0);
  466.  
  467.     return;
  468. }
  469.  
  470. VOID WINAPI
  471. IKSDCtrlHandler (DWORD Opcode)
  472. {
  473.     DWORD status;
  474.  
  475.     switch(Opcode)
  476.     {
  477.         case SERVICE_CONTROL_PAUSE:
  478.         // Do whatever it takes to pause here.
  479.             IKSDStatus.dwCurrentState = SERVICE_PAUSED;
  480.             break;
  481.  
  482.         case SERVICE_CONTROL_CONTINUE:
  483.         // Do whatever it takes to continue here.
  484.             IKSDStatus.dwCurrentState = SERVICE_RUNNING;
  485.             break;
  486.  
  487.         case SERVICE_CONTROL_STOP:
  488.         // Do whatever it takes to stop here.
  489.             IKSDStatus.dwWin32ExitCode = 0;
  490.             IKSDStatus.dwCurrentState  = SERVICE_STOP_PENDING;
  491.             IKSDStatus.dwCheckPoint    = 0;
  492.             IKSDStatus.dwWaitHint      = 0;
  493.  
  494.             if (!SetServiceStatus (IKSDStatusHandle, &IKSDStatus))
  495.             {
  496.                 status = GetLastError();
  497.                 SvcDebugOut(" [IKSD] SetServiceStatus error %ld\n",
  498.                              status);
  499.             }
  500.  
  501.             iksd_started = 0;
  502.             kill_children();
  503.             SvcDebugOut(" [IKSD] Leaving IKSD \n",0);
  504.             return;
  505.  
  506.         case SERVICE_CONTROL_INTERROGATE:
  507.         // Fall through to send current status.
  508.             break;
  509.  
  510.         default:
  511.             SvcDebugOut(" [IKSD] Unrecognized opcode %ld\n",
  512.                 Opcode);
  513.     }
  514.  
  515.     // Send current status.
  516.     if (!SetServiceStatus (IKSDStatusHandle,  &IKSDStatus))
  517.     {
  518.         status = GetLastError();
  519.         SvcDebugOut(" [IKSD] SetServiceStatus error %ld\n",status);
  520.     }
  521.     return;
  522. }
  523.  
  524.  
  525. // Stub initialization function.
  526. int
  527. ParseCmdLine( int argc, char * argv[], DWORD * specificError )
  528. {
  529.     int len = 0, i ;
  530.     char * p = NULL ;
  531.     static struct servent *service, servrec;
  532.     int arg = 1;
  533.  
  534.     /* Set up some defaults */
  535.     ports[portcount].showcmd = SW_SHOWNORMAL;
  536.     service = getservbyname("kermit", "tcp");
  537.  
  538.     /* Allocate the max needed memory */
  539.     for ( i = 1 ; i < argc ; i++ )
  540.         len += strlen( argv[i] ) + 1 ;
  541.  
  542.     ports[portcount].k95cmd = (char *) malloc( len+1 ) ;
  543.     if ( !ports[portcount].k95cmd )
  544.     {
  545.         SvcDebugOut("memory allocation error\n",0) ;
  546.         *specificError = 1;
  547.         return 0;
  548.     }
  549.     ports[portcount].k95cmd[0] = '\0' ;
  550.  
  551.     /* Process each command line option */
  552.     for ( i=1 ; i<argc ; i++ )
  553.     {
  554.         if ( argv[arg][0] == '-' && argv[arg][1] == '-' ) {
  555.             if ( !_stricmp("--maximized",argv[arg]) ) {
  556.                 ports[portcount].showcmd = SW_SHOWMAXIMIZED;
  557.                 continue;
  558.             }
  559.             else if ( !_stricmp("--minimized",argv[arg]) ) {
  560.                 ports[portcount].showcmd = SW_SHOWMINIMIZED;
  561.                 continue;
  562.             }
  563.             else if ( !_stricmp("--normal",argv[arg]) ) {
  564.                 ports[portcount].showcmd = SW_NORMAL;
  565.                 continue;
  566.             }
  567.             else if ( !_stricmp("--minnoactive",argv[arg]) ) {
  568.                 ports[portcount].showcmd = SW_SHOWMINNOACTIVE;
  569.                 continue;
  570.             }
  571.             else if ( !_strnicmp("--port:",argv[arg],7) ) {
  572.                 p = &argv[arg][7];
  573.                 if (isdigit(*p)) {                      /* Use socket number without lookup */
  574.                     service = &servrec;
  575.                     service->s_port = htons((unsigned short)atoi(p));
  576.                 } else {                                /* Otherwise lookup the service name */
  577.                     service = getservbyname(p, "tcp");
  578.                 }
  579.                 continue;
  580.             }
  581.         }
  582.  
  583.         if ( ports[portcount].k95cmd[0] )
  584.             strcat( ports[portcount].k95cmd, " ");
  585.         strcat( ports[portcount].k95cmd, argv[i] );
  586.     }
  587.  
  588.     if ( service )
  589.         ports[portcount].id = service->s_port;
  590.     else
  591.         ports[portcount].id = htons( 1649 );
  592.  
  593.     *specificError = 0;
  594.     portcount++ ;
  595.     return portcount ;
  596. }
  597.  
  598. HANDLE
  599. StartKermit( int socket, char * cmdline, int ShowCmd, int *psockdup )
  600. {
  601. #ifdef NT
  602.    PROCESS_INFORMATION StartKermitProcessInfo ;
  603.    OSVERSIONINFO osverinfo ;
  604.    STARTUPINFO si ;
  605.    HANDLE sockdup = INVALID_HANDLE_VALUE ;
  606.    static HANDLE hCurrent = INVALID_HANDLE_VALUE;
  607.    static char buf[512] ;
  608.  
  609.    osverinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO) ;
  610.    GetVersionEx( &osverinfo ) ;
  611.  
  612.    memset( &si, 0, sizeof(STARTUPINFO) ) ;
  613.    si.cb = sizeof(STARTUPINFO);
  614.    si.dwFlags = STARTF_USESHOWWINDOW;
  615.    si.wShowWindow = ShowCmd;
  616.     
  617.     if ( hCurrent == INVALID_HANDLE_VALUE )
  618.         hCurrent = GetCurrentProcess();
  619.  
  620.     *psockdup = (int)INVALID_HANDLE_VALUE;
  621.  
  622.    if (!DuplicateHandle( hCurrent, (HANDLE) socket,
  623.                     hCurrent, &sockdup,
  624.                     DUPLICATE_SAME_ACCESS, TRUE,
  625.                     DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS ))
  626.    {
  627.        SvcDebugOut( "\nINTERNET KERMIT SERVICE DAEMON FATAL ERROR:\n",0 );
  628.        SvcDebugOut(" You are using a WinSOCK which does not allow socket handles\n",0);
  629.        SvcDebugOut(" to be duplicated or shared with child processes.\n\n",0);
  630.        SvcDebugOut(" If you are attempting to start Kermit 95 Host Mode,\n",0);
  631.        SvcDebugOut(" please change SESSIONS to 1 in your configuration.\n",0);
  632.        SvcDebugOut("\n Press ENTER to exit...\n",0);
  633.        fscanf( stdin, "" ) ;
  634.        return(INVALID_HANDLE_VALUE) ;
  635.    }
  636.  
  637.     /* First try IKSDNT.EXE */
  638. #ifdef MSDEV
  639.     strcpy( buf, "msdev.exe iksdnt.exe -# 132 -A " ) ;
  640. #else
  641.     strcpy( buf, "iksdnt.exe -# 132 -A " ) ;
  642. #endif /* DEBUG */
  643.     ltoa( (LONG) sockdup, buf+strlen(buf), 10 ) ;
  644.     strcat( buf, " " );
  645.     strcat( buf, cmdline ) ;
  646.  
  647.     SvcDebugOut("Executing: ",0);
  648.     SvcDebugOut(buf,0) ;
  649.     SvcDebugOut("\n",0);
  650.  
  651.     if (CreateProcess(
  652.                        (LPSTR)NULL,          /* start K-95  */
  653.                        (LPSTR)buf, /* give it the file */
  654.                        (LPSECURITY_ATTRIBUTES)NULL,
  655.                        (LPSECURITY_ATTRIBUTES)NULL,
  656.                         TRUE,                      /* fix if necessary */
  657.                        (DWORD) CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP,
  658.                        (LPVOID)NULL,                /* fix if necessary */
  659.                        (LPSTR)NULL,               /* Current directory */
  660.                        &si,                     /* Startup info, fix */
  661.                        &StartKermitProcessInfo  /* Process info */
  662.                       ))
  663.     {
  664.         CloseHandle(StartKermitProcessInfo.hThread);
  665.         *psockdup = (int)sockdup;
  666.         return (StartKermitProcessInfo.hProcess);
  667.     }
  668.  
  669.     /* If that fails then try K95.EXE */
  670. #ifdef MSDEV
  671.     strcpy( buf, "msdev.exe k95.exe -# 132 -A " ) ;
  672. #else
  673.     strcpy( buf, "k95.exe -# 132 -A " ) ;
  674. #endif /* DEBUG */
  675.     ltoa( (LONG) sockdup, buf+strlen(buf), 10 ) ;
  676.     strcat( buf, " " );
  677.     strcat( buf, cmdline ) ;
  678.  
  679.     SvcDebugOut("Executing: \n",0);
  680.     SvcDebugOut(buf,0) ;
  681.     SvcDebugOut("\n",0);
  682.     if (CreateProcess(
  683.                        (LPSTR)NULL,          /* start K-95  */
  684.                        (LPSTR)buf, /* give it the file */
  685.                        (LPSECURITY_ATTRIBUTES)NULL,
  686.                        (LPSECURITY_ATTRIBUTES)NULL,
  687.                         TRUE,                      /* fix if necessary */
  688.                        (DWORD) CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP,
  689.                        (LPVOID)NULL,                /* fix if necessary */
  690.                        (LPSTR)NULL,               /* Current directory */
  691.                        &si,                     /* Startup info, fix */
  692.                        &StartKermitProcessInfo  /* Process info */
  693.                       ))
  694.     {
  695.         CloseHandle(StartKermitProcessInfo.hThread);
  696.         *psockdup = (int)sockdup;
  697.         return (StartKermitProcessInfo.hProcess);
  698.     }
  699.  
  700.     SvcDebugOut("CreateProcess() failed gle=%ul\n",GetLastError());
  701.     CloseHandle(sockdup) ;
  702.     return(INVALID_HANDLE_VALUE);
  703. #else /* NT */
  704.     Not built for OS/2 yet.
  705. #endif /* NT */
  706. }
  707.  
  708.  
  709. // Stub initialization function.
  710. DWORD
  711. IKSDInitialization(DWORD   argc, LPTSTR  *argv,
  712.     DWORD *specificError)
  713. {
  714.     char *p=NULL, * dbdir=NULL, dbfile[256];
  715.     int i, x;
  716.     int on = 1, rc = 0;
  717. #ifdef NT
  718.     WSADATA data ;
  719.     OSVERSIONINFO osverinfo ;
  720.  
  721.     SvcDebugOut("Internet Kermit Service Daemon\n",0);
  722.     rc = WSAStartup( MAKEWORD( 2, 0 ), &data ) ;
  723.     if ( rc == WSAVERNOTSUPPORTED )
  724.     {
  725.       WSACleanup() ;
  726.       rc = WSAStartup( MAKEWORD( 1, 1 ), &data ) ;
  727.    }
  728. #else /* NT */
  729.  
  730. #endif /* NT */
  731.  
  732.     if (ParseCmdLine( argc, argv, specificError ) == 0)
  733.         return 1;
  734.  
  735.     if ( !portcount )
  736.     {
  737. #ifdef MSDEV
  738.         ports[portcount].showcmd = SW_NORMAL;
  739. #else
  740.         ports[portcount].showcmd = SW_SHOWMINNOACTIVE;
  741. #endif
  742.         ports[portcount].k95cmd = (char *) malloc( 1 ) ;
  743.         ports[portcount].k95cmd[0] = '\0' ;
  744.         ports[portcount].id = htons( 1649 ) ;
  745.         portcount++;
  746.     }
  747.  
  748. #ifdef NT
  749.     osverinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO) ;
  750.     GetVersionEx( &osverinfo ) ;
  751.  
  752.     if (osverinfo.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS) {
  753.         dbdir = getenv("SystemRoot");
  754.     } else {
  755.         dbdir = getenv("winbootdir");
  756.         if (!dbdir)
  757.             dbdir = getenv("windir");
  758.     }
  759.     if (!dbdir)
  760.         dbdir = "C:/";
  761. #else /* NT */
  762.     dbdir = "C:/";
  763. #endif /* NT */
  764.     sprintf(dbfile,"%s\\iksd.lck",dbdir);
  765.     unlink(dbfile);
  766.     sprintf(dbfile,"%s\\iksd.db",dbdir);
  767.     unlink(dbfile);
  768.  
  769.     if ( open_sockets(specificError) )
  770.         return(1);
  771.     return 0;
  772. }
  773.  
  774.  
  775. BOOL
  776. IsInstalled()
  777. {
  778.     BOOL bResult = FALSE;
  779.     SC_HANDLE hSCM;
  780.     SC_HANDLE hService;
  781.  
  782.     // Open the Service Control Manager
  783.     hSCM = OpenSCManager( NULL, // local machine
  784.                           NULL, // ServicesActive database
  785.                           SC_MANAGER_ALL_ACCESS); // full access
  786.     if (hSCM) {
  787.  
  788.         // Try to open the service
  789.         hService = OpenService( hSCM,
  790.                                 "IKSD",
  791.                                 SERVICE_QUERY_CONFIG);
  792.         if (hService) {
  793.             bResult = TRUE;
  794.             CloseServiceHandle(hService);
  795.         }
  796.  
  797.         CloseServiceHandle(hSCM);
  798.     }
  799.  
  800.     return bResult;
  801. }
  802.  
  803. BOOL
  804. Install()
  805. {
  806.     char szFilePath[_MAX_PATH];
  807.     SC_HANDLE hSCM;
  808.     SC_HANDLE hService;
  809.     char szKey[256];
  810.     HKEY hKey = NULL;
  811.     DWORD dwData;
  812.  
  813.     // Open the Service Control Manager
  814.     hSCM = OpenSCManager( NULL, // local machine
  815.                           NULL, // ServicesActive database
  816.                           SC_MANAGER_ALL_ACCESS); // full access
  817.     if (!hSCM)
  818.         return FALSE;
  819.  
  820.     // Get the executable file path
  821.     GetModuleFileName(NULL, szFilePath, sizeof(szFilePath));
  822.  
  823.     // Create the service
  824.     hService = CreateService( hSCM,
  825.                               "IKSD",
  826.                               "IKSD",
  827.                               SERVICE_ALL_ACCESS,
  828.                               SERVICE_WIN32_OWN_PROCESS,
  829.                               SERVICE_AUTO_START,        // start condition
  830.                               SERVICE_ERROR_NORMAL,
  831.                               szFilePath,
  832.                               NULL,
  833.                               NULL,
  834.                               NULL,
  835.                               NULL,
  836.                               NULL);
  837.     if (!hService) {
  838.         CloseServiceHandle(hSCM);
  839.         return FALSE;
  840.     }
  841.  
  842.     // make registry entries to support logging messages
  843.     // Add the source name as a subkey under the Application
  844.     // key in the EventLog service portion of the registry.
  845.     strcpy(szKey, "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\IKSD");
  846.     if (RegCreateKey(HKEY_LOCAL_MACHINE, szKey, &hKey) != ERROR_SUCCESS) {
  847.         CloseServiceHandle(hService);
  848.         CloseServiceHandle(hSCM);
  849.         return FALSE;
  850.     }
  851.  
  852.     // Add the Event ID message-file name to the 'EventMessageFile' subkey.
  853.     RegSetValueEx( hKey,
  854.                    "EventMessageFile",
  855.                     0,
  856.                     REG_EXPAND_SZ,
  857.                     (CONST BYTE*)szFilePath,
  858.                     strlen(szFilePath) + 1);
  859.  
  860.     // Set the supported types flags.
  861.     dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE;
  862.     RegSetValueEx( hKey,
  863.                    "TypesSupported",
  864.                     0,
  865.                     REG_DWORD,
  866.                     (CONST BYTE*)&dwData,
  867.                      sizeof(DWORD));
  868.     RegCloseKey(hKey);
  869.  
  870.     // LogEvent(EVENTLOG_INFORMATION_TYPE, EVMSG_INSTALLED, "IKSD");
  871.  
  872.     // tidy up
  873.     CloseServiceHandle(hService);
  874.     CloseServiceHandle(hSCM);
  875.     return TRUE;
  876. }
  877.  
  878. BOOL
  879. Uninstall()
  880. {
  881.     BOOL bResult = FALSE;
  882.     SC_HANDLE hService;
  883.     SC_HANDLE hSCM;
  884.  
  885.     // Open the Service Control Manager
  886.     hSCM = OpenSCManager( NULL, // local machine
  887.                           NULL, // ServicesActive database
  888.                           SC_MANAGER_ALL_ACCESS); // full access
  889.     if (!hSCM)
  890.         return FALSE;
  891.  
  892.     hService = OpenService( hSCM,
  893.                             "IKSD",
  894.                             DELETE);
  895.     if (hService) {
  896.         if (DeleteService(hService)) {
  897.             // LogEvent(EVENTLOG_INFORMATION_TYPE, EVMSG_REMOVED, "IKSD");
  898.             bResult = TRUE;
  899.         } else {
  900.             // LogEvent(EVENTLOG_ERROR_TYPE, EVMSG_NOTREMOVED, "IKSD");
  901.         }
  902.         CloseServiceHandle(hService);
  903.     }
  904.  
  905.     CloseServiceHandle(hSCM);
  906.     return bResult;
  907. }
  908.  
  909. // Returns TRUE if it found an arg it recognised, FALSE if not
  910. // Note: processing some arguments causes output to stdout to be generated.
  911. BOOL
  912. ParseStandardArgs(int argc, char* argv[])
  913. {
  914.     char szFilePath[_MAX_PATH];
  915.  
  916.     // See if we have any command line args we recognize
  917.     if (argc <= 1)
  918.         return FALSE;
  919.  
  920.     if ( _stricmp(argv[1], "-h") == 0 ||
  921.          _stricmp(argv[1], "-?") == 0 ||
  922.          _stricmp(argv[1], "/h") == 0 ||
  923.          _stricmp(argv[1], "/?") == 0) {
  924.  
  925.         //
  926.         GetModuleFileName(NULL, szFilePath, sizeof(szFilePath));
  927.         printf("usage: %s [-v | -i | -u | -h]\r\n",szFilePath);
  928.         return TRUE;
  929.     } else if (_stricmp(argv[1], "-v") == 0 ||
  930.                _stricmp(argv[1], "/v") == 0 ) {
  931.  
  932.         // Spit out version info
  933.         printf("IKSD Version 0.1\n",0);
  934.         printf("The service is %s installed\n",
  935.                IsInstalled() ? "currently" : "not");
  936.         return TRUE; // say we processed the argument
  937.  
  938.     } else if (_stricmp(argv[1], "-i") == 0 ||
  939.                _stricmp(argv[1], "/i") == 0) {
  940.  
  941.         // Request to install.
  942.         if (IsInstalled()) {
  943.             printf("%s is already installed\n", "IKSD");
  944.         } else {
  945.             // Try and install the copy that's running
  946.             if (Install()) {
  947.                 printf("%s installed\n", "IKSD");
  948.             } else {
  949.                 printf("%s failed to install. Error %d\n", "IKSD", GetLastError());
  950.             }
  951.         }
  952.         return TRUE; // say we processed the argument
  953.  
  954.     } else if (_stricmp(argv[1], "-u") == 0 ||
  955.                _stricmp(argv[1], "/u") == 0) {
  956.  
  957.         // Request to uninstall.
  958.         if (!IsInstalled()) {
  959.             printf("%s is not installed\n", "IKSD");
  960.         } else {
  961.             // Try and remove the copy that's installed
  962.             if (Uninstall()) {
  963.                 // Get the executable file path
  964.                 GetModuleFileName(NULL, szFilePath, sizeof(szFilePath));
  965.                 printf("%s removed. (You must delete the file (%s) yourself.)\n",
  966.                        "IKSD", szFilePath);
  967.             } else {
  968.                 printf("Could not remove %s. Error %d\n", "IKSD", GetLastError());
  969.             }
  970.         }
  971.         return TRUE; // say we processed the argument
  972.  
  973.     }
  974.  
  975.     // Don't recognise the args
  976.     return FALSE;
  977. }
  978.