FTP-Serverabsicherung per Exitpunkten schaut im ersten Moment kompliziert aus, ist es aber nicht.
Der Text ist ziemlich lang, dafür vollständig.


Der Befehl WRKREGINF zeigt die vielen Exit-Punkte im IP-System an.


Wenn beim Anmelden am FTP-Server ein CL laufen soll, muss man es im FTP-Login-Exitpunkt "QIBM_QTMF_SVR_LOGON TCPL0100" eintragen.
Bei mir z.B. SERVICES/FTPANMELDC.


Wenn bei Erhalt eines FTP-Kommandos ein CL laufen soll, muss man es im FTP-Login-Exitpunkt "QIBM_QTMF_SERVER_REQ VLRQ0100" eintragen.
Bei mir z.B. SERVICES/FTPKOMMC.


Die CLs bekommen vom FTP-Server viele Parameter, siehe unten.


----------------------------




Das Anmelde-CL SERVICES/FTPANMELDC schaut so aus. Hab ich aus einer IBM-Doku kopiert, nur die letzten 3 Zeilen sind von mir.
&RETCODOUT sagt ob er Login darf oder nicht darf.


PGM PARM(&FTPREXIN &USERIN &USRLENIN &PASSWDIN +
&PASSLENIN &IPADRIN &IPLENIN &RETCODOUT +
&USEROUT &PASSWDOUT &CURLIBOUT)
/* DCL OF PARAMETERS, MUST BE EXACTLY LIKE THIS */
DCL VAR(&FTPREXIN) TYPE(*CHAR) LEN(4) /* 1=FTP 2=REXEC*/
DCL VAR(&USERIN) TYPE(*CHAR) LEN(999)/* USER ID */
DCL VAR(&USRLENIN) TYPE(*CHAR) LEN(4) /* LENGTH USR ID*/
DCL VAR(&PASSWDIN) TYPE(*CHAR) LEN(999)/* PASSWORD */
DCL VAR(&PASSLENIN) TYPE(*CHAR) LEN(4) /* LENGTH PASSWO*/
DCL VAR(&IPADRIN) TYPE(*CHAR) LEN(15) /* IP ADDRESS PC*/
DCL VAR(&IPLENIN) TYPE(*CHAR) LEN(4) /* LENGTH IP ADD*/
DCL VAR(&RETCODOUT) TYPE(*CHAR) LEN(4) /* 0=REJECT 1=OK*/
DCL VAR(&USEROUT) TYPE(*CHAR) LEN(10) /* AS/400 USER */
DCL VAR(&PASSWDOUT) TYPE(*CHAR) LEN(10) /* AS/400 PASSWO*/
DCL VAR(&CURLIBOUT) TYPE(*CHAR) LEN(10) /* AS/400 CURLIB*/
/* DCL PARAMETERS, WHICH CANT BE USED LIKE THEY COME IN */
DCL VAR(&USER10) TYPE(*CHAR) LEN(10) VALUE(' ')
DCL VAR(&USRLENDEC) TYPE(*DEC) LEN(5 0)
/* COPY THESE PARAMETERS INTO THE LOCAL COPYS: */
CHGVAR VAR(&USRLENDEC) VALUE(%BINARY(&USRLENIN))
CHGVAR VAR(&USER10) VALUE(%SST(&USERIN 1 &USRLENDEC))
/* DEFAULT OUT PARM SETTING = REJECT */
CHGVAR VAR(%BINARY(&RETCODOUT)) VALUE(0)
/* IN CASE OF ABEND: SEE DSPLOG+F4+TIME 5 MINUTES AGO */
/* OR WRKSPLF QTCP */


/* Nächste 3 Zeilen von mir*/
OVRDBF FILE(FTPAUTHL0) TOFILE(SERVICE/FTPAUTHL0)
OVRDBF FILE(FTPLOGP) TOFILE(SERVICE/FTPLOGP)
CALL PGM(SERVICE/FTPLOGIN) PARM(&USER10 &IPADRIN +
&RETCODOUT)
END: ENDPGM


FTPLOGIN ist ein Cobolprogramm, das die Datei FTPAUTHL0 liest (da drin steht wer sich von welchen IP-Ranges an welchen Wochentagen/Uhrzeiten anmelden darf), und FTPLOGP schreibt. Wie detailliert man das mit der Authorisierung treiben will, muss jeder selber entscheiden/programmieren.
Parameter:
LINKAGE SECTION.
01 P-USER PIC X(10).
01 P-IPADRESSE PIC X(15).
01 P-RETURNCODE PIC 9(8) COMP-4. <-- Man beachte das Format!

PIC 9(8) COMP-4 : Reinschreiben tut man einfach 0 oder 1.


----------------------------------


Das Befehle-erlauben-verbieten-Log-CL SERVICES/FTPKOMMC schaut so aus.
Wieder aus IBM-Doku kopiert, nur ganz unten ist von mir.


PGM PARM(&APPIDIN &OPIDIN &USRPRF &IPADRIN &IPLENIN +
&OPINFOIN &OPLENIN &RETCODOUT)
DCL VAR(&APPIDIN) TYPE(*CHAR) LEN(4) /* Application */
DCL VAR(&OPIDIN) TYPE(*CHAR) LEN(4) /* Operation */
DCL VAR(&USRPRF) TYPE(*CHAR) LEN(10) /* User */
DCL VAR(&IPADRIN) TYPE(*CHAR) LEN(15) /* IP ADDR */
DCL VAR(&IPLENIN) TYPE(*CHAR) LEN(4) /* IP Length */
DCL VAR(&OPLENIN) TYPE(*CHAR) LEN(4) /* Length of +
operation-specific info. */
DCL VAR(&OPINFOIN) TYPE(*CHAR) LEN(9999) /* +
Operation-specific information */
DCL VAR(&RETCODOUT) TYPE(*CHAR) LEN(4) /* Out-Parm */


/* FTP-Befehl auf 80 Stellen abschneiden, da variabel bis 9999 lang: */
DCL VAR(&OPINFO80) TYPE(*CHAR) LEN(80)
CHGVAR VAR(&OPINFO80) VALUE(&OPINFOIN)
OVRDBF FILE(FTPAUTHL0) TOFILE(SERVICE/FTPAUTHL0)
OVRDBF FILE(FTPLOGP) TOFILE(SERVICE/FTPLOGP)
CALL PGM(SERVICES/FTPKOMM) PARM(&OPIDIN &USRPRF +
&IPADRIN &OPINFO80 &RETCODOUT)


END: ENDPGM




SERVICES/FTPKOMM ist ein Cobolprogramm, das wie man sieht Operation, User, IP, FTP-Befehl erhält und RETCODOUT 0=Nein, 1=Ja ausgibt.
In FTPAUTHL0 stehen die erlaubten Befehle. Wie detailliert man das betreiben/programmieren will muss jeder selber wissen.
Parameter:
LINKAGE SECTION.
01 P-OPIDIN PIC X(4).
01 P-USER PIC X(10).
01 P-IPADRESSE PIC X(15).
01 P-OPINFO80 PIC X(80).
01 P-RETURNCODE PIC 9(8) COMP-4. <-- !!!






Besonderheit Parameterfeld "&OPIDIN (Operation)":
Die FTP-Befehle haben Nummern, man kann also sehr einfach einem User Befehle erlauben/verbieten.
0 = incoming connection (Anmeldeversuch)
1 = Directory/library creation
2 = Directory/library deletion
3 = change directory
4 = list directory
5 = File deletion
6 = GET
7 = PUT
8 = Rename file
9 = QUOTE RCMD


Besonderheit "&OPINFOIN (FTP-Kommando)":
Man bekommt nicht den Original-FTP-Befehl sondern so was:
PUT >/home/verkauf/verk170316.csv
GET >/QSYS.LIB/TRANSLIB.LIB/STAIST.FILE
Wenn man get/put auf Dateiebene begrenzen will, ist im Cobol/RPG-Programm etwas Stringhandling erforderlich, um rauszufinden, welche Datei er übertragen will.




-----------------------------------------------------------


Das hier steht auch noch in der IBM-Doku:
/************************************************** ****************************/
/* Additional notes: */
/* 1. When the application ID is 1 (FTP server) AND the operation ID is */
/* 0 (session initialization), the job is running under the QTCP */
/* user profile when the exit program is called. In ALL other cases, */
/* the job is running under the user's profile. */
/* 2. It is highly recommended that the exit program be created in a library */
/* with *PUBLIC authority set to *EXCLUDE, and the exit program itself */
/* be given a *PUBLIC authority of *EXCLUDE. The FTP server adopts */
/* authority necessary to call the exit program. */
/************************************************** ****************************/
/* Declare local copies of parameters (in format usable by CL) */
/* DCL VAR(&OPID) TYPE(*INT) LEN(4) */
/* DCL VAR(&OPLEN) TYPE(*DEC) LEN(5 0) */
/* Assign input parameters to local copies */
/* CHGVAR VAR(&OPID) VALUE(%BINARY(&OPIDIN)) */
/* CHGVAR VAR(&OPLEN) VALUE(%BINARY(&OPLENIN)) */
/* */
/* Handle operation specific info field (which is variable length) */
/* IF COND(&OPLEN = 0) THEN(CHGVAR VAR(&OPINFO) VALUE(' +
/* ')) */
/* ELSE CMD(CHGVAR VAR(&OPINFO) VALUE(%SST(&OPINFOIN 1 +
/* &OPLEN))) */