Example: FTP server logon exit program in C code

This is an example of a simple File Transfer Protocol (FTP) Server Logon exit program. It is written in C programming language.

This code is not complete, but provides a starting point to help you create your own program.

Note: By using the code examples, you agree to the terms of the Code license and disclaimer information.

(Pre formatted text in the following example will flow outside the frame.)

     /* Module Description *************************************************/
     /*                                                                    */
     /**********************************************************************/
     /*                                                                    */
     /* Note:  This program is a sample only and has NOT undergone any     */
     /        formal review or testing.                                    */
     /*                                                                    */
     /**********************************************************************/
     /*                                                                    */ 
     /* Source File Name: qtmfsvrlgn.c                                     */ 
     /*                                                                    */ 
     /* Module Name: FTP Server Logon exit program.                        */ 
     /*                                                                    */ 
     /* Service Program Name:  n/a                                         */ 
     /*                                                                    */ 
     /* Source File Description:                                           */ 
     /*   This example exit program provides additional control over the   */ 
     /*    process of authenticating a user to a TCP/IP application server.*/ 
     /*    When installed, this example exit program would be called each  */ 
     /*    time a user attempts to log on to the server.                   */ 
     /*                                                                    */ 
     /**********************************************************************/
     /*                                                                    */ 
     /* Function List: main       - FTP Server Logon exit program main.    */ 
     /*                qtmfsvrlgn - FTP Server Logon exit function.        */ 
     /*                CheckClientAddress - Check originating sessions IP  */ 
     /*                                      address.                      */ 
     /*                                                                    */ 
     /* End Module Description *********************************************/ 
     #define _QTMFSVRLGN_C 



     /**********************************************************************/
     /* All file scoped includes go here                                   */ 
     /**********************************************************************/
     #ifndef __stdio_h 
     #include <stdio.h> 
     #endif 

     #ifndef __ctype_h 
     #include <ctype.h> 
     #endif 

     #ifndef __string_h 
     #include <string.h> 
     #endif 

     #ifndef __stdlib_h 
     #include <stdlib.h> 
     #endif 

     #include "qusec.h"            /* Include for API error code structure */ 
     #include "qsyrusri.h"         /* Include for User Information API     */ 

     /**********************************************************************/
     /* All file scoped Constants go here                                  */ 
     /**********************************************************************/
     #define  EQ      == 
     #define  NEQ     != 
     #define  BLANK   ' ' 
     #define  FWIDTH  128            /* Width of one database file record  */ 
     #define  FNAME   21             /* Qualified database file name width */ 

     /* Valid characters for Client IP address. The CheckClientAddress()   */ 
     /*  function will check the Client IP address input argument          */ 
     /*  (ClientIPaddr_p) to ensure it is in valid dotted-decimal format.  */ 
     /*  This is one example of an input validity check.                   */ 
     const char ValidChars[] = "0123456789."; 
     /**********************************************************************/
     /* All file scoped type declarations go here                          */ 
     /**********************************************************************/


     /**********************************************************************/
      /* All file-scoped macro calls go here                                */ 
     /**********************************************************************/


     /**********************************************************************/
     /* All internal function prototypes go here                           */ 
     /**********************************************************************/

     static void qtmfsvrlgn 
         (int,char *,int,char *,int,char *,int,int *,char *,char *,char *); 

     static int CheckClientAddress(char *, int); 


     /**********************************************************************/
     /* All file scoped variable declarations go here                      */ 
     /**********************************************************************/


     /**********************************************************************/
     /*                            ** NOTE **                              */ 
     /* The following client IP address are for example purposes only. Any */ 
     /* resemblance to actual system IP addresses is purely coincidental.  */ 
     /**********************************************************************/

     /* EXCLUSIVE system lists, ie - Logon attempts from any client IP     */ 
     /*                              addresses NOT in one of these lists   */ 
     /*                              are allowed to continue.              */ 
     /* Reject server logon attempts of users attempting to log in from    */ 
     /*  these client systems (return code = 0)                            */ 
     char Reject[] = "1.2.3.4 5.6.7.8"; 
     /* Limit logon abilities of users attempting to log in as ANONYMOUS   */ 
     /*  from these client systems (return code = 6).                      */ 
     /*  In this example program, the initial current library is set and   */ 
     /*  returned as an output parameter for users attempting to log in    */ 
     /*  as ANONYMOUS from these specific client systems.                  */ 
     char Limit[] = "9.8.7.6 4.3.2.1 8.7.6.5"; 

     /* Function Specification *********************************************/ 
     /*                                                                    */ 
     /* Function Name: Main                                                */ 
     /*                                                                    */ 
     /* Descriptive Name: FTP Server Logon exit program main.              */ 
     /*                                                                    */ 
     /*    This example exit program allows access to a TCP/IP server to   */ 
     /*    be controlled by the address of the originating session, gives  */ 
     /*    additional control over the initial current library to a user,  */ 
     /*    and provides the capability to implement "anonymous" FTP.       */ 
     /*                                                                    */ 
     /* Notes:                                                             */ 
     /*                                                                    */ 
     /*   Dependencies:                                                    */ 
     /*     FTP Server Logon exit point QIBM_QTMF_SVR_LOGON was registered */ 
     /*     during FTP product installation.                               */ 
     /*                                                                    */ 
     /*   Restrictions:                                                    */ 
     /*                                                                    */ 
     /*       None                                                         */ 
     /*                                                                    */ 
     /*   Messages:                                                        */ 
     /*                                                                    */ 
     /*       None                                                         */ 
     /*                                                                    */ 
     /*   Side Effects:                                                    */ 
     /*                                                                    */ 
     /*       None                                                         */ 
     /*                                                                    */ 
     /*   Functions/Macros called:                                         */ 
     /*                                                                    */ 
     /*       qtmfsvrlgn - Server Logon exit function.                     */ 
     /*                                                                    */ 


     /* Input:                                                             */ 
     /*   int  * argv[1]     - Identifies requesting application           */ 
     /*                         (FTP Client =0, FTP Server = 1).           */ 
     /*   char * argv[2]     - User identifier from client program.        */ 
     /*                         (For FTP server, this is user CMD data     */ 
     /*   int  * argv[3]     - Length (in bytes) of User ID string.        */ 
     /*   char * argv[4]     - Authentication string from client.          */ 
     /*                         (For FTP server, this is the password)     */ 
     /*   int  * argv[5]     - Length (bytes) Authentication string.       */ 
     /*   char * argv[6]     - Internet Protocol address from which        */ 
     /*                         the session originates.                    */ 
     /*   int  * argv[7]     - Length (in bytes) of IP address.            */ 
     /*   int  * argv[8]     - Return code (received as 0).                */ 
     /*   char * argv[9]     - User profile (received as blanks).          */ 
     /*   char * argv[10]    - Password (received as blanks).              */ 
     /*   char * argv[11]    - Initial current library (received as blanks)*/ 
     /*                                                                    */ 
     /* Exit Normal: Return Return Code, User Profile, Password, Initial   */ 
     /*              Current Library to server application.                */ 
     /*                                                                    */ 
     /* Exit Error: None                                                   */ 
     /*                                                                    */ 
     /* End Function Specification *****************************************/ 
     void main(int argc, char *argv[]) 
     { 
      /********************************************************************/
      /* Code                                                             */ 
      /********************************************************************/

      /********************************************************************/
      /* Collect input arguments and call function to determine if client */ 
      /*  should be allowed to log in to an FTP server application.       */ 
      /********************************************************************/
      qtmfsvrlgn(*((int *)(argv[1])), /* Application Identifier 
     (Input) */ 
                  argv[2],             /* User Identifier         (Input) */ 
                  *((int *)(argv[3])), /* Length User of 
     Identifier(Input) */ 
                  argv[4],             /* Authentication String   (Input) */ 
                  *((int *)(argv[5])), /* Length of Authentication string */ 
     (Input) */ 
                  argv[6],             /* Client IP Address       (Input) */ 
                  *((int *)(argv[7])), /* Length of Client IP Address     */ 
     (Input) */ 
                  (int *)(argv[8]),    /* Return Code             (Output)*/ 
                  argv[9],             /* User Profile            (Output)*/ 
                  argv[10],            /* Password                (Output)*/ 
                  argv[11]);           /* Initial Current Library (Output)*/ 
       return; 
     } 



     /* Function Specification *********************************************/ 
     /*                                                                    */ 
     /* Function Name: qtmfsvrlgn                                          */ 
     /*                                                                    */ 
     /* Descriptive Name: Server Logon exit function.                      */ 
     /*                                                                    */ 
     /*   This exit function provides control over user authentication to  */ 
     /*    an FTP server.                                                  */ 
     /*                                                                    */ 
     /* Notes:                                                             */ 
     /*                                                                    */ 
     /*   Dependencies:                                                    */ 
     /*                                                                    */ 
     /*       FTP Server Logon exit point QIBM_QTMF_SVR_LOGON was          */ 
     /*        registered during FTP product installation.                 */ 
     /*                                                                    */ 
     /*   Restrictions:                                                    */ 
     /*                                                                    */ 
     /*       None                                                         */ 
     /*                                                                    */ 
     /*   Messages:                                                        */ 
     /*                                                                    */ 
     /*       None                                                         */ 
     /*                                                                    */ 
     /*   Side Effects:                                                    */ 
     /*                                                                    */ 
     /*       None                                                         */ 
     /*                                                                    */ 
     /*   Functions/Macros called:                                         */ 
     /*                                                                    */ 
     /*       CheckClientAddress - Check the ClientIPaddr_p input argument.*/ 
     /*       memcpy  - Copy bytes from source to destination.             */ 
     /*       memset  - Set bytes to value.                                */ 
     /*       strstr  - Locate first occurrence of substring.              */ 
     /*       sprintf - Formatted print to buffer.                         */ 
     /*                                                                    */ 
     /* Input:                                                             */ 
     /*   int    ApplId            - Application Identifier (Server = 1).  */ 
     /*   char * UserId_p          - User identifier from client program.  */ 
     /*                              (For FTP server, USER subcommand data)*/ 
     /*   int    Lgth_UserId       - Length (in bytes) of user ID string.  */ 
     /*   char * AuthStr_p         - Authentication string from client.    */ 
     /*                              (For FTP server, this is the password)*/ 
     /*   int    Lgth_AuthStr      - Length (bytes) Authentication string. */ 
     /*   char * ClientIPaddr_p    - Internet Protocol address from which  */ 
     /*                              the session originates.               */ 
     /*   int *  Lgth_ClientIPaddr - Length (in bytes) of IP address.      */ 
     /*                                                                    */ 


     /* Output:                                                            */ 
     /*   int * ReturnCode: Indicates degree of success of operation:      */ 
     /*        ReturnCode = 0 - Reject logon.                              */ 
     /*        ReturnCode = 1 - Continue logon; use initial current library*/ 
     /*        ReturnCode = 2 - Continue logon; override initial current   */ 
     /*                         library                                    */ 
     /*        ReturnCode = 3 - Continue logon; override user, password    */ 
     /*        ReturnCode = 4 - Continue logon; override user, password,   */ 
     /*                         current library                            */ 
     /*        ReturnCode = 5 - Accept logon; override user profile        */ 
     /*        ReturnCode = 6 - Accept logon; override user profile,       */ 
     /*                         current library                            */ 
     /*   char * UserProfile  - User profile to use for this session       */ 
     /*   char * Password     - Password to use for this session           */ 
     /*   char * Init_Cur_Lib - Initial current library for this session   */ 
     /*                                                                    */ 
     /* Exit Normal: (See OUTPUT)                                          */ 
     /*                                                                    */ 
     /* Exit Error:  None                                                  */ 
     /*                                                                    */ 
     /* End Function Specification *****************************************/ 
     static void qtmfsvrlgn(int ApplId,                    /* Entry point  */ 
                             char *UserId_p, 
                             int Lgth_UserId, 
                             char *AuthStr_p, 
                             int Lgth_AuthStr, 
                             char *ClientIPaddr_p, 
                             int Lgth_ClientIPaddr, 
                             int *ReturnCode, 
                             char *UserProfile_p, 
                             char *Password_p, 
                             char *InitCurrLib_p) 
     { 
       /********************************************************************/
       /* Local Variables                                                  */ 
       /********************************************************************/
       /* The following lists serve as an example of an additional layer   */ 
       /*  of control over user authentication to an application server.   */ 
       /*  Here, logon operations using the following user identifiers     */ 
       /*  will be allowed to continue, but the output parameters returned */ 
       /*  by this example exit program will vary depending on which list  */ 
       /*  a user identifier (UserId_p) is found in.         */ 
       /*  For example, attempts to logon as FTPUSR11 or FTPUSR2 will be   */ 
       /*  allowed, and this example exit will return the initial current  */ 
       /*  library as an output parameter along with a return code of 2.   */ 
       /********************************************************************/
       /* Continue the logon operation, Return Code = 1                    */ 
       char Return1[] = "FTPUSR10  "; 
       /* Continue the logon operation, Return Code = 2                    */ 
       char Return2[] = "FTPUSR11  FTPUSR2   "; 
       /* Continue the logon operation, Return Code = 3                    */ 
       char Return3[] = "FTPUSR12  FTPUSR3   FTPUSR23  "; 
       /* Continue the logon operation, Return Code = 4                    */ 
       char Return4[] = "FTPUSER   FTPUSR4   FTPUSR24  FTPUSR94  ";
       int rc;                       /* Results of server logon request    */ 
       Qsy_USRI0300_T Receiver_var;  /* QSYRUSRI API Receiver variable     */ 
       int   Lgth_Receiver_var;      /* Receiver variable length           */ 
       char  Format_Name[8];     /* Format name buffer           */
       char  User_Id[10];        /* User Identifier buffer       */
       Qus_EC_t error_code =         /* QSYRUSRI API error code structure: */ 
       { 
        sizeof(Qus_EC_t),      /* Set bytes provided         */ 
        0,                                   /* Initialize bytes available */ 
        ' ',' ',' ',' ',' ',' ',' '          /* Initialize Exception Id    */ 
       }; 
       char *pcTest_p;               /*  Upper-case User Identifier pointer*/ 
       int i;                        /* "For" loop counter variable        */ 



       /********************************************************************/
       /* Code                                                             */ 
       /********************************************************************/

       /* Test validity of application ID input argument.                  */ 
       if(1 NEQ ApplId) 
         { 
         /* ERROR - Not FTP server application.                            */ 
         /*         Return Code of 0 is used here to indicate              */ 
         /*         that an incorrect input argument was received.         */ 
         /*         The server logon operation will be rejected.           */ 
         rc = 0;                               /* Application ID not valid */ 
         }      /* End If the application identifier is NOT for FTP server */ 
       else                       /* FTP server application identifier     */ 
         { 
         /* Validate the client IP address input argument.                 */ 
         rc = CheckClientAddress(ClientIPaddr_p, 
                           Lgth_ClientIPaddr); 
         if(0 NEQ rc)                  /* Valid, acceptable client address */ 
           { 
           /* Initialize User_Id; used to hold upper-cased user identifier */ 
           memset(User_Id, BLANK, sizeof(User_Id)); 

           /* Initialize pcTest_p to point to UserId_p input argument.     */ 
           pcTest_p = UserId_p; 

           /* Uppercase all of the user ID to compare for ANONYMOUS user.  */ 
           for(i = 0; i < Lgth_UserId; i++) 
             { 
             User_Id[i] = (char)toupper(*pcTest_p); 
             pcTest_p += 1; 
             } 

           /* If user has logged in as ANONYMOUS.                          */ 
           if(0 == memcmp("ANONYMOUS ", User_Id, 10)) 
             { 
             /* Determine how to continue with ANONYMOUS logon attempt.    */ 
             if(NULL NEQ strstr(Limit, ClientIPaddr_p)) 
               { 
               /* If users system IP address is found in the "Limit" list, */ 
               /*  return ReturnCode of 6, user profile and initial        */ 
               /*  current library values as output parameters.            */ 
               memcpy(UserProfile_p, "USERA1    ", 10); 
               memcpy(InitCurrLib_p, "PUBLIC    ", 10); 
               rc = 6; 
               } 
             else 
               { 
               /* Users system IP address is NOT found in the "Limit" list,*/ 
               /*  return ReturnCode of 5, user profile output parameter;  */ 
               /* use the initial current library that is specified by the */ 
               /* user profile information.                                */ 
               memcpy(UserProfile_p, "USERA1    ", 10); 
               rc = 5; 
               } 
             }                                 /* End If USER is ANONYMOUS */ 


           else                          /* Else USER is not ANONYMOUS     */ 
             { 
             /* Set receiver variable length.                              */ 
             Lgth_Receiver_var = sizeof(Qsy_USRI0300_T); 
             /* Set return information format.                             */ 
             memcpy(Format_Name, "USRI0300", sizeof(Format_Name)); 
             /* Set user identifier passed in.                             */ 
             memset(User_Id, BLANK, sizeof(User_Id)); 
             memcpy(User_Id, UserId_p, Lgth_UserId); 
             /* Call QSYRUSRI - Retrieve User Information API              */ 
             QSYRUSRI(&Receiver_var,    /* Return Information receiver var */ 
                      Lgth_Receiver_var,/* Receiver variable length        */ 
                      Format_Name,      /* Return information format name  */ 
                      User_Id,          /* User ID seeking information     */ 
                      &error_code);     /* Error return information        */ 
             /* Check if an error occurred (byte_available not equal 0)    */ 
             if(0 NEQ error_code.Bytes_Available) 
               { 
               /* Return ReturnCode of 0 only (Reject logon);              */ 
               rc = 0;                      /* Reject the logon operation  */ 
               *ReturnCode = rc;            /* Assign result to ReturnCode */ 
               } 
             else          /* No error occurred from Retrieve User Info    */ 
               {           /* (Bytes_Available = 0)                        */ 
               /* Set current library for user profile.                    */ 
               memcpy(InitCurrLib_p, Receiver_var.Current_Library, 10); 
               if(NULL NEQ strstr("*CRTDFT   ", 
                                 Receiver_var.Current_Library)) 
                 { 
                 memcpy(InitCurrLib_p, "FTPDEFAULT", 10); 
                 } 
               else 
                 { 
                 if(NULL NEQ strstr(Return1, UserId_p)) 
                   { 
                   /* Return ReturnCode of 1 (Continue logon);             */ 
                   /*  Also return user profile and password output        */ 
                   /*  parameters to endure they are ignored by the server.*/ 
                   memcpy(UserProfile_p, UserId_p, Lgth_UserId); 
                   memcpy(Password_p, AuthStr_p, Lgth_AuthStr); 
                   rc = 1;                 /* Continue the logon operation */ 

                   } 
                 else 
                   { 
                   if(NULL NEQ strstr(Return2, UserId_p)) 
                     { 
                     /* Return ReturnCode of 2, and initial current library*/ 
                     /*  Also return user profile and password values      */ 
                     /*  even though they will be ignored by the server.   */ 
                     memcpy(UserProfile_p, UserId_p, Lgth_UserId); 
                     memcpy(Password_p, AuthStr_p, Lgth_AuthStr); 
                     memcpy(InitCurrLib_p, "FTPEXT2", 
                                           strlen("FTPEXT2")); 
                     rc = 2;          /* Continue logon; return InitCurLib */ 
                     } 


                   else 
                     { 
                     if(NULL NEQ strstr(Return3, UserId_p)) 
                       { 
                       /* Return ReturnCode of 3, user profile, password.  */ 
                       /*  Also return initial current library value,      */ 
                       /*  even though it will be ignored.                 */ 
                       memcpy(UserProfile_p, UserId_p, Lgth_UserId); 
                       memcpy(Password_p, AuthStr_p, Lgth_AuthStr);

                       memcpy(InitCurrLib_p, "FTPEXT3", 
                                     strlen("FTPEXT3")); /* Server ignores */ 
                       rc = 3; 
                       } 
                     else 
                       { 
                       if(NULL NEQ strstr(Return4, UserId_p)) 
                         { 
                         /*Return ReturnCode of 4, user profile,           */ 
                         /* password, and initial current library values   */ 
                         memcpy(UserProfile_p, UserId_p, Lgth_UserId); 
                         memcpy(Password_p, AuthStr_p, Lgth_AuthStr); 
                         memcpy(InitCurrLib_p, "FTPEXT4", 
                                                strlen("FTPEXT4"));

                         rc = 4; 
                         } 
                       else 
                         /* This is the default return code for logon      */ 
                         /* attempts using any user identifier not         */ 
                         /* explicitly found in one of the four lists in   */ 
                         /* the local variables section of this function.  */ 
                         { 
                         /*Return ReturnCode of 1, continue logon operation*/ 
                         rc = 1; 
                         } 
                       } 
                     } 
                   } 
                 } 
               }             /* End No error occurred (byte_available = 0) */ 
             }             /* End Else USER is not ANONYMOUS               */ 
           }             /* End Valid, acceptable client address           */ 
         }             /* End FTP server application identifier            */ 
       *ReturnCode = rc; 
       return; 
     }                                         /* End program qtmfsvrlgn.c */ 




     /* Function Specification *********************************************/ 
     /*                                                                    */ 
     /* Function Name: CheckClientAddress                                  */ 
     /*                                                                    */ 
     /* Descriptive Name: Check the IP address of the originating session  */ 
     /*                    from the input argument (ClientIPaddr_p) to     */ 
     /*                    ensure it is in valid dotted-decimal format,    */ 
     /*                    and that the client system is allowed access.   */ 
     /*                    This is an example of an input validity check.  */ 
     /*                                                                    */ 
     /* Notes:                                                             */ 
     /*                                                                    */ 
     /*   Dependencies:                                                    */ 
     /*      None                                                          */ 
     /*                                                                    */ 
     /*   Restrictions:                                                    */ 
     /*       None                                                         */ 
     /*                                                                    */ 
     /*   Messages:                                                        */ 
     /*       None                                                         */ 
     /*                                                                    */ 
     /*   Side Effects:                                                    */ 
     /*       None                                                         */ 
     /*                                                                    */ 
     /*   Functions/Macros called:                                         */ 
     /*                                                                    */ 
     /*       strspn - Search for first occurrence of a string.            */ 
     /*                                                                    */ 
     /* Input:                                                             */ 
     /*   char * ClientIPaddr_p    - Internet Protocol address from which  */ 
     /*                              the session originates.               */ 
     /*   int *  Lgth_ClientIPaddr - Length (in bytes) of IP address.      */ 
     /*                                                                    */ 
     /* Output:                                                            */ 
     /*   int    rc                - Return code indicating validity of IP */ 
     /*                              address from ClientIPaddr_p input.    */ 
     /*                            0 = Reject the logon operation.         */ 
     /*                                ClientIPaddr_p is one that is not   */ 
     /*                                allowed, or contains a character    */ 
     /*                                that is not valid.                  */ 
     /*                            1 = Continue the logon operation.       */ 
     /*                                                                    */ 
     /* Exit Normal: (See OUTPUT)                                          */ 
     /*                                                                    */ 
     /* Exit Error:  None.                                                 */ 
     /*                                                                    */ 
     /* End Function Specification *****************************************/ 


     static int CheckClientAddress(char *ClientIPaddr_p,  /* Entry point */ 
                                     int Lgth_ClientIPaddr) 
     { 
       /********************************************************************/
       /* Local Variables                                                  */
       /********************************************************************/
       int rc;                                              /* Return code */ 

       /********************************************************************/
       /* Code                                                             */ 
       /********************************************************************/

       /* Check that client IP address input argument is dotted-decimal    */ 
       /*  format of minimum length, with no leading blanks or periods,    */ 
       /*  and contains only valid characters.                             */ 
       if((Lgth_ClientIPaddr < 7) ||         /* Minimum IP address size */ 
          (strspn(ClientIPaddr_p, ValidChars) < Lgth_ClientIPaddr)|| 
          (strspn(ClientIPaddr_p, ".") EQ 1)||  /* Leading '.' in IP       */ 
          (strspn(ClientIPaddr_p, " ") EQ 1))   /* Leading blank in IP     */ 
         { 
         /* Client's IP address not valid, or contains an incorrect character */ 
         rc = 0;               /* Client IP address input argument not valid  */ 
         } 
       else 
         { 
         /* Is client system allowed to log in to FTP server?              */ 
         if(NULL NEQ strstr(Reject, ClientIPaddr_p)) 
           { 
           /* Return code = 0 - Reject the server logon operation, as the  */ 
           /*                   client IP address is found in the global   */ 
           /*                   "Reject" list.                             */ 
           rc = 0;                         /* Reject the logon operation   */ 
           } 
         else 
           { 
           /* Continue the server logon operation checks.                  */ 
           rc = 1;                         /* Continue the logon operation */ 
           } 
         } 
       return(rc); 
     } 

     #undef _QTMFSVRLGN_C