home *** CD-ROM | disk | FTP | other *** search
- /*****************************************************************************
- *
- * MODULE NAME : AREXECD.C
- *
- * COPYRIGHTS:
- * This module contains code made available by IBM
- * Corporation on an AS IS basis. Any one receiving the
- * module is considered to be licensed under IBM copyrights
- * to use the IBM-provided source code in any way he or she
- * deems fit, including copying it, compiling it, modifying
- * it, and redistributing it, with or without
- * modifications. No license under any IBM patents or
- * patent applications is to be implied from this copyright
- * license.
- *
- * A user of the module should understand that IBM cannot
- * provide technical support for the module and will not be
- * responsible for any consequences of use of the program.
- *
- * Any notices, including this one, are not to be removed
- * from the module without the prior written consent of
- * IBM.
- *
- * AUTHOR: Peter J. Schwaller
- * VNET: PJS at RALVM6 Tie Line: 444-4376
- * Internet: pjs@ralvm6.vnet.ibm.com (919) 254-4376
- *
- * FUNCTION: This module is the server side of AREXEC. This module
- * will execute a specified command and route the output
- * back to the AREXEC transaction program.
- *
- * AVAILABILITY:
- * These sample programs and source are also available on
- * CompuServe through the APPC Information Exchange. To get
- * to the APPC forum just type 'GO APPC' from any CompuServe
- * prompt. The samples are available in the Sample Programs
- * library section. Just search on the keyword CPICPGMS to
- * find all the samples in this series.
- *
- * Updates for the sample programs and support for many more
- * CPI-C platforms will also be made available on CompuServe.
- *
- * RELATED FILES:
- * See AREXEC.DOC for usage instructions.
- *
- * CHANGE HISTORY:
- * Date Description
- * 06/15/92 NS/DOS accepts version 2.02 into system test.
- * 08/05/92 Version 2.31 released to CompuServe
- * This version was also distributed at the APPC/APPN Platform
- * Developer's Conference held in Raleigh, NC.
- * 08/13/92 Changed all printf and fprintf calls to use a write_*() call.
- * 08/24/92 Version 2.32 released to CompuServe.
- * 09/22/92 Version 2.33 released to CompuServe.
- * 11/17/92 Supports sending operating system string - see CPICERR.C
- * Version 2.34 released to CompuServe
- * 01/07/93 Version 2.35
- * Fixed a number of problems when compiling with IBM C Set/2
- * password input was displayed
- * timer resolution was 1 second
- * arexecd server did not function properly
- *
- *****************************************************************************/
-
- #ifdef WIN32 /*WIN32*/
- #include <windows.h> /*WIN32*/
- SERVICE_STATUS_HANDLE stat_hand; /*WIN32*/
- SERVICE_STATUS servstat; /*WIN32*/
- #endif /*WIN32*/
-
- #include "wincpic.h"
-
- /* standard C include files */
- #include <string.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <stddef.h>
-
- /* Set up constant declarations */
- #include "cpicdefs.h"
-
- /* Collection of routines with special ported version for each platform */
- #include "cpicport.h"
-
- #define MAX_COMMAND_LENGTH 500
-
- /*--------------------------------------------------------------------------*/
- /* CPI-C Error Handling Global Variables */
- /*--------------------------------------------------------------------------*/
- #include "cpicerrs.h" /* CPI-C error handling vars. */
- CPICERR * cpicerr;
-
- /* Define these here so we can make changes throughout the code. */
- /*
- * The PROGRAM_INFO string should be kept in sync with the
- * MAJOR_VERSION and MINOR_VERSION constants. Although the
- * cpicerr_exchange_version() call will support values up to 255,
- * values for MINOR_VERSION should be from 00-99 to maintain the
- * two character format in the version string.
- */
- #define PROGRAM_NAME "AREXECD"
- #define PROGRAM_INFO "version 2.35"
- #define MAJOR_VERSION (2)
- #define MINOR_VERSION (35)
- #define LOG_FILE_NAME "arexecd.err"
- #define LOG_FILE_PATH "$LOGPATH"
-
-
- char * intro[] = {
- PROGRAM_NAME " " PROGRAM_INFO " - Remote execution of a command. (Server)",
- NULL
- };
-
-
- void
- TPStart(void)
- {
- /* Variables used for CPI-C calls */
- unsigned char cm_conv_id[8]; /* CPI-C conversation ID */
- CM_INT32 temp; /*WIN32*/
- CM_INT32 cm_rc; /* CPI-C return code */
- CM_INT32 length; /* generic length variable */
- CM_INT32 rts_received; /* request to send received */
- CM_INT32 max_receive_len; /* Max receive length on CMRCV */
- CM_INT32 what_received; /* What received parm from CMRCV */
- CM_INT32 received_len; /* Amount of data rcvd on CMRCV */
- CM_INT32 status_received; /* Status from CMRCV */
-
- /* Data buffer for send and receive */
- char buffer[MAX_COMMAND_LENGTH]; /* CPIC data buffer */
-
- char partner_major_version;
- char partner_minor_version;
-
- unsigned char destination[MAX_FQPLU_NAME];
-
- show_info(intro);
-
- #ifdef WIN32
- {
- /**********************************************************************/
- /* Initialisation for WinCPIC */
- /**********************************************************************/
- unsigned short WinCPICVERSION = 0x0001;
- WCPICDATA CPICData;
- if (WinCPICStartup(WinCPICVERSION,&CPICData))
- {
- return;
- }
- /**********************************************************************/
- /* Set our local TP Name */
- /**********************************************************************/
- temp=7;
- cmsltp("AREXECD",&temp,&cm_rc);
- }
- #endif
-
- /*
- * Initialize the CPICERR structure. This is done before the CMINIT
- * call so that we can use CPICERR for help with errors on CMINIT.
- * The procedure is in CPICERR.C
- */
- cpicerr = cpicerr_new();
- cpicerr_set_program_name(cpicerr, PROGRAM_NAME);
- cpicerr_set_program_info(cpicerr, PROGRAM_INFO);
- cpicerr_set_major_version(cpicerr, MAJOR_VERSION);
- cpicerr_set_minor_version(cpicerr, MINOR_VERSION);
- cpicerr_set_log_file_name(cpicerr, LOG_FILE_NAME);
- cpicerr_set_log_file_path(cpicerr, LOG_FILE_PATH);
-
- cmaccp(cm_conv_id,
- &cm_rc);
- /*
- * Note that as we have used cmsltp to specify our local TP name,
- * cmaccp may return asynchronously, so we must do a cmwait
- */
- if (cm_rc == CM_OPERATION_INCOMPLETE) /*WIN32*/
- { /*WIN32*/
- cmwait(cm_conv_id, &cm_rc, &temp); /*WIN32*/
- } /*WIN32*/
-
- /*------------------------------------------------------------------------*
- * Fill in conversation information for CPI-C error reporting.
- *------------------------------------------------------------------------*/
- cpicerr_set_conv_id(cpicerr, cm_conv_id);
-
- if (cm_rc != CM_OK) {
- cpicerr_handle_rc(cpicerr, MSG_CMACCP, cm_rc);
- } else {
- length = 17;
- cmepln(cm_conv_id,
- destination,
- &length,
- &cm_rc );
- destination[(unsigned int)length] = '\0';
- write_output("\nContacted by partner: ");
- write_output("%s", destination);
- write_output("\n");
- }
-
- cpicerr_exchange_version(cpicerr,
- cm_conv_id,
- CM_RECEIVE_STATE,
- &partner_major_version,
- &partner_minor_version);
-
- {
- CM_SEND_TYPE send_type = CM_SEND_AND_FLUSH;
- cmsst(cm_conv_id, /* Set send type */
- &send_type,
- &cm_rc);
- }
-
- max_receive_len = MAX_COMMAND_LENGTH-1;
-
- cmrcv(cm_conv_id, /* Receive Data */
- (unsigned char *) buffer, /* Data Pointer */
- &max_receive_len, /* Size of Data Buffer */
- &what_received, /* returned - what received */
- &received_len, /* returned - length of data */
- &status_received, /* returned - status received */
- &rts_received, /* returned - request to send */
- &cm_rc);
-
- if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMRCV, cm_rc);
-
- buffer[(unsigned int)received_len] = '\0';
-
- convert_from_ascii(buffer, strlen(buffer));
-
- write_output("The command is:\n%s\n\n", buffer);
-
- execute_and_send_output(buffer,
- cm_conv_id,
- cpicerr);
-
- {
- CM_DEALLOCATE_TYPE deallocate_type = CM_DEALLOCATE_FLUSH;
-
- cmsdt(cm_conv_id,
- &deallocate_type,
- &cm_rc);
- }
-
- cmdeal(cm_conv_id,
- &cm_rc);
- if (cm_rc) cpicerr_handle_rc(cpicerr, MSG_CMDEAL, cm_rc);
-
- /* destroy the object we created with cpicerr_new() */
- cpicerr_destroy(cpicerr);
-
- exit(EXIT_SUCCESS);
-
- }
-
- #ifdef WIN32
- /*****************************************************************************/
- /* The following code makes this TP invokable as an NT service. There are 3 */
- /* routines. */
- /* */
- /* 1. main. This is the entry point for the process, it sets up a service */
- /* table entry and then calls StartServiceCtrlDispatcher. This call */
- /* doesn't return, but uses the thread which called it as a */
- /* control dispatcher for all the services implemented by this */
- /* process (in this case, just the TP itself). */
- /* */
- /* 2. ServiceMain. This is the main entry point for the service itself, the */
- /* service control dispatcher creates a thread to start at this */
- /* routine. It must register a service control handler for the */
- /* service which will be called by the control dispatcher when it */
- /* has control instructions for the service. It then informs the */
- /* service control manager that the service is running and finally */
- /* calls the start of the TP itself. This routine should not return */
- /* until the service is ready to die. */
- /* */
- /* 3. ControlHandler. This routine is called by the control dispatcher when */
- /* it has instructions for the service. We do not respond to any */
- /* of the instructions as this service should be transitory and not */
- /* actually run for more than a few seconds so we don't need to do */
- /* anything with the STOP or SHUTDOWN requests. */
- /* Note that we MUST call SetServiceStatus, even if the status */
- /* hasn't changed. */
- /*****************************************************************************/
-
- void __cdecl main( DWORD argc, LPSTR * argv);
- void WINAPI ServiceMain(DWORD dwNumServiceArgs, LPTSTR * lpServiceArgs);
- VOID WINAPI ControlHandler(DWORD dwControl);
- SERVICE_STATUS_HANDLE stat_hand;
- SERVICE_STATUS servstat;
-
- void __cdecl main( DWORD argc, LPSTR * argv)
- {
- SERVICE_TABLE_ENTRY stab[2];
-
- /***************************************************************************/
- /* Start the control dispatcher. This call gives the SCManager this */
- /* thread for the entire period that this service is running, so that it */
- /* can call us back with service controls. It will spawn a new thread to */
- /* run the service itself, starting at entrypoint ServiceMain. */
- /***************************************************************************/
- stab[0].lpServiceName = "AREXECD\0";
- stab[0].lpServiceProc = ServiceMain;
-
- stab[1].lpServiceName = NULL;
- stab[1].lpServiceProc = NULL;
-
- StartServiceCtrlDispatcher(stab);
-
- }
-
-
- /*****************************************************************************/
- /* This routine is the entry-point for the service itself the service */
- /* control dispatcher creates a thread to start here when we issue */
- /* StartServiceControlDispatcher. */
- /* */
- /* Inputs: number of arguments to services, array of strings. */
- /* */
- /* Outputs: none */
- /* */
- /*****************************************************************************/
- void WINAPI ServiceMain(DWORD dwNumServiceArgs, LPTSTR * lpServiceArgs)
- {
-
- DWORD rc;
-
- stat_hand = RegisterServiceCtrlHandler("AREXECD\0", ControlHandler);
- if (stat_hand == (SERVICE_STATUS_HANDLE)NULL)
- {
- rc = GetLastError();
- DebugBreak();
- }
-
- /***************************************************************************/
- /* Let the SCManager know that we are running. */
- /***************************************************************************/
- servstat.dwServiceType = SERVICE_WIN32;
- servstat.dwCurrentState = SERVICE_RUNNING;
- servstat.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
- servstat.dwWin32ExitCode = NO_ERROR;
- servstat.dwServiceSpecificExitCode = NO_ERROR;
- servstat.dwCheckPoint = 0;
- servstat.dwWaitHint = 0;
-
- rc = SetServiceStatus(stat_hand, &servstat);
- if (!rc)
- {
- rc = GetLastError();
- DebugBreak();
- }
-
- TPStart();
-
- }
-
- /*****************************************************************************/
- /* This routine is the callback from the SCManager to handle specific */
- /* service control requests. It MUST call SetServiceStatus before it */
- /* returns, regardless of whether the status has changed. */
- /* */
- /* Inputs: service control requested */
- /* */
- /* Outputs: none */
- /* */
- /*****************************************************************************/
- VOID WINAPI ControlHandler(DWORD dwControl)
- {
- DWORD rc;
-
- switch (dwControl)
- {
- case SERVICE_CONTROL_STOP :
- servstat.dwCurrentState = SERVICE_STOP_PENDING;
- servstat.dwWaitHint = 24000;
- break;
-
- case SERVICE_CONTROL_PAUSE :
- case SERVICE_CONTROL_CONTINUE :
- case SERVICE_CONTROL_INTERROGATE :
- servstat.dwWaitHint = 0;
- break;
-
- case SERVICE_CONTROL_SHUTDOWN:
- servstat.dwCurrentState = SERVICE_STOP_PENDING;
- servstat.dwWaitHint = 10000;
- break;
- }
-
- rc=SetServiceStatus(stat_hand, &servstat);
- if (!rc)
- {
- rc=GetLastError();
- }
-
- }
-
- #endif