Tag Archives: IBM

DB2 PHP Security Exploit – Older versions of Zend Server for IBM i – Login under any user profile without a password

If you’re running an old version of Zend Server on the IBM i make sure you look at this article from Zend Support:

https://support.zend.com/hc/en-us/articles/203733853-db2-connect-may-allow-blank-password-with-user-entered

Basically you need to rename
/usr/local/zendsvr/lib/libdb400.a to /usr/local/zendsvr/lib/libdb400.a.bak

To do this Rod Flohr suggest you open a PASE shell and issue a mv command to rename the file.

5250 Terminal:

call qp2term

PASE:

mv /usr/local/zendsvr/lib/libdb400.a /usr/local/zendsvr/lib/libdb400.a.bak

If you pass in user supplied parameters to db2_connect function a person could log in as someone else with greater authorities possibly and go into pages or access data they aren’t authorized to use.

Advertisements

Can you run PHP on IBM Bluemix (Cloud Foundry)?

Yes! I was confused about running PHP on IBM’s Bluemix Cloud services, but thanks to Daniel Krook he pointed me in the right direction. He recommends that you use Mikusa’s build pack which has a simple 30 second tutorial on how to deploy

https://github.com/dmikusa-pivotal/cf-php-build-pack

The big confusion for me is that they have a thing called BlueMix.net and Cloud Foundry and its hard to decipher what is IBM’s cloud service. Unlike Amazon, which simply uses Amazon Webservices. “Bluemix is built on Cloud Foundry” – Bradley Holt, so BlueMix is like your app built on top of PHP runtime. They also offer runtimes for java, node.js, Ruby, BUT no PHP in their documentation https://www.ng.bluemix.net/docs/#.

More info on BlueMix and PHP from Daniel Krook: https://bitly.com/cf-for-php

Another Example: https://github.com/IBM-Bluemix/todo-apps/tree/master/php

Calling PHP from RPG via PASE

Recently I wanted the RPG developer to call my PHP program for a process we are creating. By putting the business logic in PHP it allows us to use it internally in a Green Screen Application and on our website. We needed the ability to hash a password, send an email, and update a database record. Now this could all be done strictly using RPG and ILE, but PHP has functions built into the language to accomplish these goals such as password_hash() and mail().

I looked into using “PHP101: RPG Call PHP 101” on the YIP website, but the RPG developer found the Scott Klement article which is much simpler and easier to use and understand here:

http://iprodeveloper.com/rpg-programming/run-qshellpase-commands-rpg-special-files

You’ll have to register for the article but its worth it since his article is written well and has a zip file of the source code

By following scott klement’s example you have the RPG program run a command through PASE that calls the PHP to run your script.

md = 'PATH=$PATH:/usr/local/Zend/Core/bin && +
iconv -f 37 -t 819 | +
php /www/zendcore/htdocs/MyPHPScript.php';

In his example he’s using Zend Core (the older version of PHP on i), so if your on Zend Server you’ll use these paths:

/usr/local/zendsvr/bin/php  /www/zendsvr/htdocs/MyPHPScript.php

...and if you're on Zend Server 6 or above it will be 

/usr/local/zendsvr6/bin/php and /www/zendsvr6/htdocs/MyPHPScript.php

Now to send parameters into the script you just add them to the command line command:

/usr/local/zendsvr/bin/php  /www/zendsvr/htdocs/MyPHPScript.php parameter1 parameter2 parameter3

You’ll use the $argv variable to access the parameters pass into the PHP script and use echo to send data back to the RPG program.

You may run into permissions issues with calling /usr/local/zendsvr/bin/php because Zend Server installed using QSECOFR, so you might have to add permissions to that path to the user calling PHP from RPG

Now your PHP Dev and RPG dev can collaborate on many projects that need to be done in house apps and the website! You can also try running the Command line PHP by doing CALL QP2TERM

The “gotchas” of running Zend Framework 2 on older versions of Zend Server for IBM i – ZF2 skeleton Application

Have you tried the ZF2 skeleton Application on PHP on the IBM i and have run into issues getting it to work since your on ZS 5.5, 6.x and are unable to upgrade to ZS7 at the moment? Well here’s a few gotchas and things you’ll have to change to get it work correctly:


 

Fatal error: Can’t inherit abstract function Zend\Validator\Translator\TranslatorInterface::translate() (previously declared abstract in Zend\I18n\Translator\TranslatorInterface) in library/Zend/Mvc/I18n/Translator.php on line 19

1) Comment out the Translate method in i89n\Translator\TranslatorInterface.php

//public function translate($message, $textDomain = 'default', $locale = null);
//For some reason ZF2 has 2 methods with the same name but it works in newer versions of PHP

 

Zend\ServiceManager\Exception\ServiceNotFoundException

zendframework/library/Zend/ServiceManager/ServiceManager.php:529

Zend\ServiceManager\ServiceManager::get was unable to fetch or create an instance for Zend\Db\Adapter\Adapter

2) set your config_glob_paths to the full path of the config/application.config.php. Note: the path below has to be specific to where your file is located on the IFS.

'config_glob_paths' => array(
      '/www/zendsvr/htdocs/zf2test/config/autoload/{,*.}{global,local}.php',
),
//AFter updating to ZS 7 you should be able to change this back to the relative path of config/autoload/{,*.}{global,local}.php

 

“album” in MYLIB type *FILE not found. SQLCODE=-204

3) Add ‘platform_options’ to your config/autoload/global.php

//The SQL that is generated by Zend's classes is putting quotes around the table like:
//SELECT 'album'.* FROM 'album'
//after turning off quote_identifiers it will run this SQL:
//SELECT album.* FROM album
return array(
     'db' => array(
         'driver'           => 'IbmDb2',
         'platform'         => 'IbmDb2',
         'platform_options' => array('quote_identifiers' => false),
         'database'         => '*LOCAL', // IBM i serial number or db directory entry name goes here
         'persistent' => true,
        'driver_options'    => array(
            'autocommit'     => DB2_AUTOCOMMIT_OFF, //::TODO:: We might not be able to use the constant since db2 may have not loaded at this point
            'i5_naming'     => DB2_I5_NAMING_ON, //::TODO:: We might not be able to use the constant since db2 may have not loaded at this point
            'i5_lib'        => 'MYLIB',
            'i5_libl'       => 'MYLIB MYLIB2 MYLIB3',
            ),
     ),
     'service_manager' => array(
         'factories' => array(
             'Zend\Db\Adapter\Adapter'
                     => 'Zend\Db\Adapter\AdapterServiceFactory',
         ),
     ),
 );

 

You’re view doesn’t display titles or artists

4) This is because the DB2 is case-insensitive and automatically converts lower-case column names that were created in the CREATE TABLE ALBUM script to upper-case columns (i.e. title is now TITLE and artist is now ARTIST). You can either modify the CREATE TABLE sql to force lower case column names by putting double quotes around your columns ( i.e. “title” “artist”). If you do it this way you’ll always have to put double quotes around it when using SQL, but in the PHP it won’t require double quotes. OR you can change the Album Model’s exchangeArray() to use the upper case column names. I recommend using the upper-case columns because the Zend\Db\Adapter\Driver\IbmDb2\ibmdb2 Statement class doesn’t know that it has to put double quotes around lowercase field names. The only approach with this is that you’ll have to change the field names to uppercase throughout the Getting Started Example

Solution 1

/* Creating table MYLIB.ALBUM */
DROP Table MYLIB.ALBUM;
CREATE TABLE MYLIB.ALBUM (
    'id' INTEGER GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1, NO ORDER, NO CYCLE, NO MINVALUE, NO MAXVALUE, CACHE 20) NOT HIDDEN ,
    'artist' VARCHAR (100) NOT NULL NOT HIDDEN ,
    'title' VARCHAR (100) NOT NULL NOT HIDDEN ,
    PRIMARY KEY ('id')
) NOT VOLATILE ;

LABEL ON TABLE MYLIB.ALBUM IS 'Test table for ZF2' ;

 INSERT INTO MYLIB.ALBUM ('artist', 'title')
     VALUES  ('The  Military  Wives',  'In  My  Dreams');
 INSERT INTO MYLIB.ALBUM ('artist', 'title')
     VALUES  ('Adele',  '21');
 INSERT INTO MYLIB.ALBUM ('artist', 'title')
     VALUES  ('Bruce  Springsteen',  'Wrecking Ball (Deluxe)');
 INSERT INTO MYLIB.ALBUM ('artist', 'title')
     VALUES  ('Lana  Del  Rey',  'Born  To  Die');
 INSERT INTO MYLIB.ALBUM ('artist', 'title')
     VALUES  ('Gotye',  'Making  Mirrors');

GRANT SELECT,INSERT,UPDATE,DELETE ON MYLIB.ALBUM TO MYUSER;
SELECT * FROM MYLIB.ALBUM

Solution 2

<?php
namespace Album\Model;

 class Album
 {
     public $id;
     public $artist;
     public $title;

     public function exchangeArray($data)
     {
     //SOLUTION 2 - change the PHP file to use the upper-case column names
         $this->id     = (!empty($data['ID'])) ? $data['ID'] : null;
         $this->artist = (!empty($data['ARTIST'])) ? $data['ARTIST'] : null;
         $this->title  = (!empty($data['TITLE'])) ? $data['TITLE'] : null;
     }

	 public function getInputFilter()
     {
         if (!$this->inputFilter) {
             $inputFilter = new InputFilter();

             $inputFilter->add(array(
                 'name'     => 'ID',
                 'required' => true,
                 'filters'  => array(
                     array('name' => 'Int'),
                 ),
             ));

             $inputFilter->add(array(
                 'name'     => 'ARTIST',
                 'required' => true,
                 'filters'  => array(
                     array('name' => 'StripTags'),
                     array('name' => 'StringTrim'),
                 ),
                 'validators' => array(
                     array(
                         'name'    => 'StringLength',
                         'options' => array(
                             'encoding' => 'UTF-8',
                             'min'      => 1,
                             'max'      => 100,
                         ),
                     ),
                 ),
             ));

             $inputFilter->add(array(
                 'name'     => 'TITLE',
                 'required' => true,
                 'filters'  => array(
                     array('name' => 'StripTags'),
                     array('name' => 'StringTrim'),
                 ),
                 'validators' => array(
                     array(
                         'name'    => 'StringLength',
                         'options' => array(
                             'encoding' => 'UTF-8',
                             'min'      => 1,
                             'max'      => 100,
                         ),
                     ),
                 ),
             ));

             $this->inputFilter = $inputFilter;
         }

         return $this->inputFilter;
     }
 }

class AlbumForm extends Form
 {
     public function __construct($name = null)
     {
         // we want to ignore the name passed
         parent::__construct('album');

         $this->add(array(
             'name' => 'ID',
             'type' => 'Hidden',
         ));
         $this->add(array(
             'name' => 'TITLE',
             'type' => 'Text',
             'options' => array(
                 'label' => 'Title',
             ),
         ));
         $this->add(array(
             'name' => 'ARTIST',
             'type' => 'Text',
             'options' => array(
                 'label' => 'Artist',
             ),
         ));
         $this->add(array(
             'name' => 'submit',
             'type' => 'Submit',
             'attributes' => array(
                 'value' => 'Go',
                 'id' => 'submitbutton',
             ),
         ));
     }
 }

Fatal error: Can’t inherit abstract function Zend\Form\LabelAwareInterface::setLabel() (previously declared abstract in Zend\Form\ElementInterface) in /www/zendsvr/htdocs/zf2test/vendor/zendframework/zendframework/library/Zend/Form/Element.php on line 21

5) Comment out setlabel and getlabel in Zend/Form/View/LabelAwareInterface.php – https://github.com/zendframework/zf2/issues/5996

//public function setLabel($label);
    //public function getLabel();

Doctrine is not supported for the IBM DB2

This isn’t a ZF2 issue directly, but if you try and use ZF2 plugins such as ZFCuser you’ll run into issues. Doctrine doesn’t work that well with IBM DB2 currently. The current implementation is based on DB2 for Linux. There is talk about creating new classes that would handle the IBM DB2 specifically but there hasn’t been any work on it. A conversation looking into solving this is being had at – https://github.com/doctrine/dbal/pull/518 . Novice PHP programmers remember that there’s multiple ways of solving a problem and doctrine is not a must have to get the job done.

UPDATE on Case-sensitivity – Dec 3 2014

I think some of the case sensitivity issues can be fixed if Zend Framework’s Zend\Db\Adapter\Driver\IbmDb2\ibmdb2 is updated to use QSYS2.DELIMIT_NAME which is available in V7R1 TR 8 and V7R2. Also doctrine could be used if they used that feature. Not everyone is on that Version of the OS so this would need to be a feature that should be explicitly set. More info on QSYS2.DELIMIT_NAME – http://www.itjungle.com/fhg/fhg111214-story01.html

Migrating from Zend Core for I to Zend Server for IBM I – My Experience

I’m currently working on migrating from Zend Core 2.6.0 to Zender Server 5.6  for IBM I.  Big thanks to Alan Seiden who has some very helpful blog posts on this topic.  I’d recommend checking out:

http://www.alanseiden.com/2010/04/21/differences-between-zend-core-and-zend-server-on-ibm-i/

and

http://www.alanseiden.com/2011/02/08/qa-upgrading-from-zend-core-to-zend-server/

Here’s my tip from migrating:

  1. If you were using the I5_* functions for database connections you can continue using AURA equipments toolkit, but I think long term you’d be better off using PHP db2_* functions.  Do not use the Zend Framework’s DB2 class since the db2_bind param doesn’t work.  The ZF team can’t implement it to work correctly right now and probably never will in the future.  I’ve been waiting 3 years now for them to make a change…
  2. Use http://as400:2001/HTTPAdmin to change the apache config for Zend Server and to start/stop the server
  3. You’ll need to trasfer your files from /www/zendcore to /www/zendsrv
  4. Give Permissions to QTMHHTTP.
    Run STRQSH
    cd /www/zendsvr/htdocs
    chmod –R 770
    chown -R qtmhhttp
  5. Modify the http.conf file and compare your old conf file to see if changes need to made
    /www/zendcore/conf/http.conf
    /www/zendsvr/conf/http.conf
  6. #–Check your system CCSID value ( dspsysval qccsid). if the value is 65535 then add the following two directives to Apache configuration file (/www/zendsvr/conf/httpd.conf) and then Stop and Start Apache:
    DefaultFsCCSID 37
    CGIJobCCSID 37
  7. Edit the php.ini file and add a different session path (edit /usr/local/zendsvr/etc/php.ini)
    session.save_path = “/tmp/ZS”
  8. Change scripts that reference www/zendcore to www/zendsvr
  9.  Recreate any NFS mounts since files might have moved into /www/zendsvr
  10. IF your using Zend Framework you might want to continue using the old version that Zend Core had, so modify your php.ini file include path to include it and not include the new version which is currently 1.11.10
    include_path = “.:/usr/local/Zend/ZendFramework/library:/usr/local/zendsvr/share/pear:/usr/local/ZendSvr/share/ToolkitApi”
Benefits of upgrading from Zend Core:
  1. PERFORMANCE!  I’m seeing scripts running between 18%-400% faster.  One script used to take 40 seconds now only takes 8 seconds.
  2. Only 1 apache configuration to worry about now
  3. Latest PHP

iSeries Access 64 Bit Driver problems Segmentation Faults

Update: May 17 2016 – At common I found out that 64 bit issues should now all be resolved when using the latest PHP 5.6, the unixODBC manager 2.2.14+ and IBM i Access for Linux ODBC driver.  This was effecting PHP extension: PDO ODBC, and ODBC_* functions

PHP 5.6.x+
http://php.net/downloads.php

UnixODBC Manager
http://www.unixodbc.org/

IBM i Access ODBC Driver [for Linux] (ibm-iaccess-1.1.0.1-1.0.x86_64)
http://www-03.ibm.com/systems/power/software/i/access/linux.html

Kevin Adler’s Article from IBM
https://www.ibm.com/developerworks/ibmi/library/i-ibmi-access-client-solutions-linux/

Segmentation Fault Problem

I’ve had a lot of trouble with using the iSeries Access 64 bit odbc driver for Linux (iSeriesAccess-5.4.0-1.6.x86_64.rpm) on my RHEL linux box to connect toa  V5R4 iSeries server.  I switched back to using the 32 bit driver and saying i’ll wait until they update the 64 bit driver to work.

I was going to the PHP page and finding just a blank screen returned to the browser, which made it a pain to debug.  I found out after looking at the apache error log file in /var/log/httpd/error_log  that there were segmentation faults with the following error:

[notice] child pid XXXXX exit signal Segmentation fault (11)

To try and debug the PHP to see what causing the problem i put die(‘here’) statements in my code until i found out where the interpretor wasn’t getting to because of the seg fault.   I found out on the return of the Zend Framework’s PDO ODBC Fetchall statement the program was causing the seg fault.  I also noticed that this only occured when i had a null field in the DB2 udb for iSeries database.  The field was a char datatype.

If you’re having this problem i’d recommend just installing the 32 bit driver(iSeriesAccess-5.4.0-1.2.i386.rpm).

Debugging

Here’s how i understand requests get called in case you want to try and debug the problem:

  1. Request for page comes in from Apache
  2. PHP runs and makes db calls through  a DSN
  3. All db calls go through unixODBC manager
  4. The db call then goes through the IBM Client Access driver you have specified and executes the sql on the iSeries.
  5. If the driver has a problem with a null field it would create a segmentation fault.

Here’s a link to someone’s explanation of the problems using the 64 bit driver:

https://www.ibm.com/developerworks/forums/thread.jspa?messageID=14510046&#14510046

Need help understanding how to install the driver and setup all the linux files (/etc/odbc.ini /etc/odbcisnt.ini)

Here’s the link to the driver download

iSeries Access Linux Driver download

Remember to edit your
/etc/odbcinst.ini

[iSeries Access ODBC Driver]

Description &amp;amp;amp;amp;nbsp; &amp;amp;amp;amp;nbsp; &amp;amp;amp;amp;nbsp; &amp;amp;amp;amp;nbsp; &amp;amp;amp;amp;nbsp; &amp;amp;amp;amp;nbsp; = iSeries Access for Linux ODBC Driver
Driver &amp;amp;amp;amp;nbsp; &amp;amp;amp;amp;nbsp; &amp;amp;amp;amp;nbsp; &amp;amp;amp;amp;nbsp; &amp;amp;amp;amp;nbsp;= /opt/ibm/iSeriesAccess/lib/libcwbodbc.so
Setup &amp;amp;amp;amp;nbsp; &amp;amp;amp;amp;nbsp; &amp;amp;amp;amp;nbsp; &amp;amp;amp;amp;nbsp; &amp;amp;amp;amp;nbsp; = /opt/ibm/iSeriesAccess/lib/libcwbodbcs.so
NOTE1 &amp;amp;amp;amp;nbsp; &amp;amp;amp;amp;nbsp; &amp;amp;amp;amp;nbsp; &amp;amp;amp;amp;nbsp; &amp;amp;amp;amp;nbsp; = If using unixODBC 2.2.11 or later and you want the 32 and 64-bit ODBC drivers to share DSN's,
NOTE2 &amp;amp;amp;amp;nbsp; &amp;amp;amp;amp;nbsp; &amp;amp;amp;amp;nbsp; &amp;amp;amp;amp;nbsp; &amp;amp;amp;amp;nbsp; = the following Driver64/Setup64 keywords will provide that support.
Driver64 &amp;amp;amp;amp;nbsp; &amp;amp;amp;amp;nbsp; &amp;amp;amp;amp;nbsp; &amp;amp;amp;amp;nbsp; &amp;amp;amp;amp;nbsp; &amp;amp;amp;amp;nbsp; &amp;amp;amp;amp;nbsp; &amp;amp;amp;amp;nbsp;= /opt/ibm/iSeriesAccess/lib64/libcwbodbc.so
Setup64 &amp;amp;amp;amp;nbsp; &amp;amp;amp;amp;nbsp; &amp;amp;amp;amp;nbsp; &amp;amp;amp;amp;nbsp; = /opt/ibm/iSeriesAccess/lib64/libcwbodbcs.so
Threading &amp;amp;amp;amp;nbsp; &amp;amp;amp;amp;nbsp; &amp;amp;amp;amp;nbsp; &amp;amp;amp;amp;nbsp; &amp;amp;amp;amp;nbsp; &amp;amp;amp;amp;nbsp; &amp;amp;amp;amp;nbsp; = 2
DontDLClose &amp;amp;amp;amp;nbsp; &amp;amp;amp;amp;nbsp; &amp;amp;amp;amp;nbsp; &amp;amp;amp;amp;nbsp; &amp;amp;amp;amp;nbsp; &amp;amp;amp;amp;nbsp; = 1
UsageCount &amp;amp;amp;amp;nbsp; &amp;amp;amp;amp;nbsp; &amp;amp;amp;amp;nbsp; &amp;amp;amp;amp;nbsp; &amp;amp;amp;amp;nbsp; &amp;amp;amp;amp;nbsp; &amp;amp;amp;amp;nbsp;= 1

and /etc/odbc.ini

[iSeriesDSN]
Description = iSeries Access ODBC Driver DSN for iSeries
Driver = iSeries Access ODBC Driver
System = iSeriesSystemName
UserID =
Password =
Naming = 0
DefaultLibraries = QGPL
Database =
ConnectionType = 0
CommitMode = 2
ExtendedDynamic = 0
DefaultPkgLibrary = QGPL
DefaultPackage = A/DEFAULT(IBM),2,0,1,0,512
AllowDataCompression = 1
LibraryView = 0
AllowUnsupportedChar = 0
ForceTranslation = 0
Trace = 0

Giving credit to IBM for this example file