Monthly Archives: January 2015

PHP IBM i Toolkit – Security Awareness of HTTP transport – Sending UserId and Password in Clear Text

With many open source security exploits coming out (shellshock, Heartbleed and recently Ghost exploits) I decided to look into the open source PHP IBM i toolkit that many people are using to access the IBMi. The whole idea of open source is that by having many eyes looking at something that bugs and security issues would be figured out and new features can be contributed by anyone. The issue I found with the PHP toolkit is that there’s no warning about using the HTTP transport to connect to the iSeries. It’s actually sending your user id and password over the network to the web server in plain text. This is an issue with the XMLService as well. It really should not allow you to connect via HTTP and should force HTTPS connections. I looked into odbc_connect and it appears to me that its doing some type of encryption as I was not able to pick up my username with wireshark. Since IBM_DB2 is using SQLConnect in the php extension i’d assume the same goes for that transport method. Therefore, by default the toolkit appears safe, but if your project requires you to connect via HTTP make sure you refactor the transport to use HTTPS instead.  Also please don’t use the GET method as it puts the parameters (the userid and password) in the url string which is sometimes saved into access logs.

You can see this issue in the send method of httpsupp class

http

To see how to securely create a https request look at the comments from: jrubenstein at gmail dot com and louis dot huppenbauer at gmail dot com on php.net’s stream_context_create

PHP IBM i toolkit – Thoughts on its future development

The PHP IBM i toolkit is a collection of PHP files that interact with XMLSERVICE on the IBM i to give you access to IBM i objects. I’ve been thinking that this approach was probably taken because it opens the doors to any programming language that wants to interact with the IBM i (PHP, Node.js, Ruby, asp.net etc… can all use this API). The problem I see with the current implementation is that requires xml encoding, xml parsing, and function calls that aren’t compiled. I think it makes sense that a PHP extension be written in C with hooks into the IBM i objects, much like how IBM_DB2.so php extension has hooks into Physical files, stored procedures, etc… IBM has C ILE that already can interact with all IBM i objects why not have a direct API to call from your PHP like db2_connect().  Your PHP project would call the compiled C PHP extension.  There’s already a starting point since you can view the source of ibm_db2.so.  Chuk from twitter mentioned creating it myself, which is tempting but unfortunately I’m not that familiar with “under the hood” of the IBM i.

IBM i PHP Toolkit

Is it all about performance? Increase in usability?

  1. There has to be a balance between performance and the ability to get the job done quickly, and easily maintainable in the future.
  2. With the PHP extension it would make it more usable as you won’t have to worry about including the CW.php wrapper.
  3. You can use the function calls provided from the php extension anywhere.
  4. Upgrades are as simple as overwriting the .so file in the php extensions folder.

Why C/C++?

  1. You can extend the functionality and performance of PHP with a compiled PHP extension.
  2. You can create C ILE on the IBM i instead of using RPG ILE.  Chris Hird says he does most of his development in C instead of RPG. If he wants to write an application on Linux he can keep using C.  RPG is proprietary and stuck on the IBM i until IBM decides to open source it.
  3. Its popular based on TIOBE rating

Alternative to toolkit to access RPG, CL programs

  1. You can create external stored procedures that attach to RPG or CL Programs (any language in drop down below)

externalproc

  1. QSYS.QCMDEXC can be called in a Stored Procedure to call CL (not sure about the other languages)
  2. The disadvantage is that you have to write and create the stored procedure for every External program.  Which is not an optimal workflow for PHP development (Write PHP, Write Stored Proc, Create Stored Proc)

What is client IBM_DB2 PHP Extension look like under the hood?

So I looked into the IBM_DB2 c source code and figured out that its more like a wrapper around SQL* ODBC functions with additional specific DB2 features added on.  So I guess that really wouldn’t be a starting point for accessing IBM i programs directly.

Responses from Twitter

TIOBE Rating

tiobeprogramming

Links

XMLSERVICE

PHP IBM i Toolkit Gihub Source

Tutorial to create PHP Extension | Another Article on PHP Extensions | More on PHP Extensions

IBM_DB2 PHP Extension Source from PECL

IBM_DB2 uses some ODBC functions and you can find info on them here

Running a cronjob (automated job) on the IBM i to call PHP

The IBM i is different from Linux environments on how you create a reoccurring batch job. You’ll create a Command Line (CL) Program that calls the PHP script and add that Program to the IBMi’s Job Scheduler. The PHP script will be called via the PHP-CLI which is the command line interpreter that doesn’t use the Apache Web Server. Parameters are passed to the script via the command line and populated in the variables: $argv,$argc.

Steps to create a reoccurring scheduled batch PHP job

1) Create the PHP script,
MyPHPScript.php

<?php
//This example script we'll write to a file so that we can look at it later and
//see if our script got called
$file = '/mydir/test.txt';
$content = file_get_contents($file);
$today = date('F j, Y, g:i a');

$content .= 'The PHP Script was ran on $today n';
file_put_contents($file, $current);
?>

2) Create a CL program that calls the PHP script using PHP-CLI in the PASE (QP2SHELL). Run STRPDM, choose 3 – work with members, choose File: QCLSRC, 3 – copy an existing CLLE/CLP program, 2 – edit the new CL member that you created and put the following in the CL:
MYLIB/MYCLPGM

CALL PGM(QP2SHELL) PARM('/usr/local/zendsvr/bin/php-cli' +
 'batchphp/MyPHPScript.php' +
 'ParameterValue1')

3) Add CL program to job scheduler (ADDJOBSCDE)

ADDJOBSCDE JOB(BATCHNAME) SCDDATE(*NONE) CMD(CALL PGM(MYLIB/MYCLPGM))
SCDDAY(*MON) SCDTIME(‘22:00’) FRQ(*WEEKLY) RCYACN(*NOSBM)
JOBD(MYLIB/MYCLJOBD)

PHP-CLI path: /usr/local/zendsvr/bin/php-cli

4) (Optional) – If the user you’re using doesn’t have permissions to PHP-CLI you’ll also have to run these commands to give them permissions

CHGAUT OBJ('/usr/local/zendsvr/') USER(YOURUSERNAME) DTAAUT(*RX) OBJAUT(*NONE)
CHGAUT OBJ('/usr/local/zendsvr/bin/') USER(YOURUSERNAME) DTAAUT(*RX) OBJAUT(*NONE)
CHGAUT OBJ('/usr/local/zendsvr/bin/php-cli') USER(YOURUSERNAME) DTAAUT(*RX) OBJAUT(*NONE)
CHGAUT OBJ('/usr/local/zendsvr/etc/') USER(YOURUSERNAME) DTAAUT(*RX) OBJAUT(*NONE)
CHGAUT OBJ('/usr/local/zendsvr/etc/zce.rc') USER(YOURUSERNAME) DTAAUT(*RX) OBJAUT(*NONE)
CHGAUT OBJ('/usr/local/zendsvr/etc/conf.d/') USER(YOURUSERNAME) DTAAUT(*RX) OBJAUT(*NONE)
CHGAUT OBJ('/usr/local/zendsvr/etc/conf.d/ibm_db2.ini') USER(YOURUSERNAME) DTAAUT(*RX) OBJAUT(*NONE)
CHGAUT OBJ('/usr/local/zendsvr/share/') USER(YOURUSERNAME) DTAAUT(*RX) OBJAUT(*NONE)
CHGAUT OBJ('/usr/local/zendsvr/share/ToolkitAPI/') USER(YOURUSERNAME) DTAAUT(*RX) OBJAUT(*NONE)
CHGAUT OBJ('/usr/local/zendsvr/share/ToolkitAPI/CW/') USER(YOURUSERNAME) DTAAUT(*RX) OBJAUT(*NONE)
CHGAUT OBJ('/usr/local/zendsvr/share/ToolkitAPI/CW/cw.php') USER(YOURUSERNAME) DTAAUT(*RX) OBJAUT(*NONE)
CHGAUT OBJ('/usr/local/zendsvr/lib/') USER(YOURUSERNAME) DTAAUT(*RX) OBJAUT(*NONE)
CHGAUT OBJ('/usr/local/zendsvr/lib/php_extensions/') USER(YOURUSERNAME) DTAAUT(*RX) OBJAUT(*NONE)
CHGAUT OBJ('/usr/local/zendsvr/lib/php_extensions/ibm_db2.so') USER(YOURUSERNAME) DTAAUT(*RX) OBJAUT(*NONE)
CHGAUT OBJ('/pathtoyourphp/MyPHPScript.php') USER(YOURUSERNAME) DTAAUT(*RX) OBJAUT(*NONE)

If you need to debug your PHP-CLI config you can do the following:
CALL QP2TERM
In QP2TERM run this command
/usr/local/zendsvr/bin/php-cli -i > phpinfo.html
This will give you the “PHPinfo()” of PHP-CLI which could be different from what your web PHPinfo shows since QTMHHTTP is probably not running this script.

To get a deeper understanding check out Alan Seiden’s slides

Debugging CL: Use this command if you want to check out the variables in your cl as it runs. F5 to step through, F22 to see hex value of the variable your cursor is on. STRISDB PGM(MYCL) UPDPROD(YES) INVPGM(NO)

Note: If you’re getting garbage passed into your CL program look into Parameter Passing. You’ll have to use *TCAT and a null variable to null terminate your strings. Here’s my example of how to null terminate the strings passed to PASE.

PHP-CLI wrapper with null terminated command and file parameter

PGM PARM(&amp;FILENAME)
/* VARS */
DCL VAR(&amp;FILENAME) TYPE(*CHAR) LEN(80)
DCL VAR(&amp;PHPCLIPATH) TYPE(*CHAR) LEN(128)
/* &amp;NULL is longer than variables above to ensure it removes all spaces X'40'*/
DCL VAR(&amp;NULL) TYPE(*CHAR) LEN(208) VALUE(X'00') /*TERMINATE VAR WITH NULL */
/* SET VARS */
/* DATA AREA USED FOR PHP-CLI PATH in case it changes*/
/* PHP-CLI = /usr/local/zendsvr/bin/php-cli*/
RTVDTAARA DTAARA(MYLIB/PHPCLIPATH) RTNVAR(&amp;PHPCLIPATH)
CHGVAR VAR(&amp;PHPCLIPATH) VALUE(&amp;PHPCLIPATH *TCAT &amp;NULL)
CHGVAR VAR(&amp;FILENAME) VALUE(&amp;FILENAME *TCAT &amp;NULL)
/* RUN */
CALL QP2SHELL PARM(&amp;PHPCLIPATH &amp;FILENAME)
ENDPGM