Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Zend Core on IBM i - Security Considerations


Published on

Talk by Tony Cairns, IBM, at ZendCon 2009

Published in: Technology
  • Login to see the comments

Zend Core on IBM i - Security Considerations

  1. 1. Zend Core for IBM i Security Considerations Tony “Ranger” Cairns
  2. 2. Developers are seeing PHP benefits but, managers are worried about PHP security. What can we do?
  3. 3. Option 1) Guarantee system security Step 1) Unplug system. Step 2) Lock in a vault.
  4. 4. Option 2) Start a security journey where valuable information assets may be used by authorized people for authorized purposes ... • Protect against outsiders – Would be web hackers – Bumbling user input • Protect against insiders – Would be corporate criminals – Careless programmers
  5. 5. An hour security pitch is not your answer... but if you believe security is a journey not a destination, this may help.
  6. 6. Step 1) Understand what we get out of the box. IBM i • RSTLICPGM I5_COMD • 5250 start / stop PASE *PGM, zend subsystem *SRVPGM • Dual Apache HTTP:89 configuration Server HTTP:8000 (Reverse Proxy) Server • i5 toolkit for program IFS access (i5_COMD) /www PHP Module • Multiple direct PHP DB2 access methods 5250 zend Zend Core subsystem admin tools DB2 UDB
  7. 7. What to protect in Zend Core for IBM i? • Internal Access (PHP) • External Access (Web) – Directories (web dirs) – ILE Apache • /www/zendcore • /www/zendcore/conf • /usr/local/Zend • httpd.conf – Stream files (web pages / scripts) – PASE Apache • /www/zendcore/htdocs • /usr/local/Zend/apache2/conf • /usr/local/Zend/apache2/htdocs • httpd.conf – Programs (web call) – PHP configuration • /qsys.lib/zendcore.lib • /usr/local/Zend/Core/etc • Toolkit called programs (RPG) • php.ini – User profiles – PHP programs (asset on ramp) • Nobody, NoGroup, etc. • db2_connect() • i5_connect()
  8. 8. Zend Core for IBM i installed profiles • NOBODY (*USER) • ZENDADMIN (*SECOFR) – PHP Apache server – Start/stop jobs in ZEND – Zend Core jobs (ZENDCOREAP) subsystem – Group = NOGROUP – Pseudo random generator (prngd) – Special authorities = *NONE – GROUP = *NONE • NOGROUP (*USER) – *ALL special authorities – Group profile • ZENDTECH (*USER) – For access to NOBODY – Update PHP configuration resources, other profiles may add – GROUP = *NONE • Group = NOGROUP – Special authorities = *NONE • MYSQL (*PGMR) – Mysql profile – Optional install – Special authorities = *NONE
  9. 9. Zend Core for IBM i access rights ... Execute Rights Access Rights I5_COMD PASE *PGM, *SRVPGM QTMHHTTP HTTP:89 CMD, ... Server (Reverse Proxy) HTTP:8000 NOBODY Server IFS NOGROUP /www/zendcore PHP /usr/local/Zend Module 5250 zend ZENDADMIN subsystem Zend Core ZENDTECH admin tools DB2 UDB *PUBLIC EXCLUDE
  10. 10. /www/zendcore • Default secure as of ZC 2.6.1 ... – Access control is no public access • /www/zendcore/* (drwxrws--- 5 nobody) – PUBLIC *EXCLUDE – NOBODY *RWX – Note: NOGROUP *RWX • /www – PUBLIC *RX – PUBLIC is not allowed access to PHP scripts or other information • Add group profile NOGROUP to other user profiles for access – QTMHHTTP – Group = NOGROUP Protect your PHP applications from public view
  11. 11. /usr/local/Zend • Default secure as of ZC 2.6.1 ... • More secure ... – Access control standard web – Access control only PHP web • /usr/local/Zend (drwxr-sr-x 5 qsecofr) • /usr/local/Zend (drwxr-s--- 5 qsecofr) – PUBLIC *RX – PUBLIC *EXCLUDE – QSECOFR *RWX (who install) • /usr – Note: NOGROUP *RX • /usr/local • /usr – PUBLIC *USE • /usr/local – Public will not be able to call PHP – PUBLIC *RX from command line or RPG program – Public is allowed access to PHP • Add group profile NOGROUP to other from command line or RPG user profiles for access program, etc. – QTMHHTTP – Group = NOGROUP Protect Zend Core web server, programs, configuration and files.
  12. 12. ZENDCORE • Default secure as of ZC 2.6.1 • More secure ... – PUBLIC *RX – PUBLIC *EXCLUDE – ZENDADMIN *RWX • Only PHP administrator can access programs (adopt QSECOFR) Protect Zend Core product library programs.
  13. 13. Apache configuration /www/zendcore/conf/httpd.conf /usr/local/Zend/apache2/conf/httpd.conf
  14. 14. Dual Apache ZC 2.6.1 (default) • ILE Apache:89 Browser HTTP:89 – Responds to any browser http://myi:89 Server – Reverse proxy (Reverse Proxy) • to PASE Apache:8000 – Configuration • http://myi:2001/HTTPAdmin->ZENDCORE – https is available • PASE Apache:8000 HTTP:8000 Browser – Responds to any browser Server http://myi:8000 – Also Reverse proxy via Apache:89 PHP Module – Configuration (edit only) • http://myi:2001/HTTPAdmin->PASENEW • /usr/local/Zend/apache2/conf/ • httpd.conf – https is available
  15. 15. Comparison of the Two HTTP Servers IBM HTTP Server Apache Server ZENDCORE server instance; using UNIX-based open source server 5722DG1 product ZENDCORE instance created and Server instance created and configured configured automatically when Zend automatically when Zend Core product is Core product is installed installed Server runs in IBM i Server runs in IBM i PASE Main function: reverse proxy server Main function: run the PHP application and return result Configure server instance using IBM Edit only configure the server using the Web Administration Tool IBM GUI (no tabs) Https available Https available, but certificates using PASE openssl tools (unfamiliar i5 folks)
  16. 16. Apache degrees of security, a matter of choice ... • PASE Apache:8000 (default) • ILE Apache:89 (default) Lower security – Reverse proxy to 8000 • ILE Apache:89 (edit) – Reverse proxy 8000 – 8000 only responds localhost • PASE SSL enabled – Using openssl • ILE Apache SSL enabled – Reverse proxy to 8000 – 8000 only responds localhost • Multiple systems – DMZ reverse proxy Higher security
  17. 17. PASE Apache Server (default) • Listens on port 8000 HTTP:89 – Only receives URL requests Server that are sent to that port httpd.conf: (Reverse Proxy) • Allows any user to make these User nobody requests Group nogroup • All data flowing between the IBM HTTP Server (Reverse Proxy) and the Apache server HTTP:8000 is not encrypted Browser Server http://myi:8000 • All data flowing on the network PHP between client and server is Module public Lower security
  18. 18. IBM HTTP Server Reverse Proxy (default) • Server instance name is: HTTP:89 Browser ZENDCORE http://myi:89 Server (Reverse Proxy) • Listens on port 89 – Only receives URL requests that are sent to that port httpd.conf: • Users are denied access if QTMHHTTP requesting any other (default) directory/files/applications HTTP:8000 Server • Forwards on those requests to PHP the Apache Server 8000 Module • Allows any user to make requests • All data flowing on the network between client and server is public Lower security
  19. 19. IBM HTTP Server Reverse Proxy (default) Modify PASE Apache for localhost (edit) • Leave HTTP Server:89 as is – Leave reverse proxy Browser HTTP:89 http://myi:89 Server • Modify PASE Apache (Reverse Proxy) – Change: • Allow from all – To httpd.conf: • Allow from Allow from • == localhost (localhost) HTTP:8000 Server PHP Module More security
  20. 20. PASE Apache 443 (https) (short “self certificate” tutorial) • Make certificate (self) – call qp2term – cd /usr/local/Zend/apache2/conf Browser – openssl req -x509 -nodes -days 365 -subj https://myi '/C=US/ST=Minnesota/L=Rochester/' -newkey rsa:4096 -keyout server.key -out server.crt – Note: CN correct for your site Encrypted • Go zendcore/zcmenu httpd_ssl.conf: – 7. Additional Apache options Include conf/ssl.conf HTTP:8000 – 2. PASE Apache Control ssl_conf: Server • /usr/local/... SSLCertificateFile PHP • http_ssl.conf /usr.../server.crt Module • S = Start (E = Stop) SSLCertificateKeyFile • https://myi5 /usr.../server.key – Get certificate (not perm) – Note https is port 443 (conflict?) Higher security
  21. 21. IBM HTTP Server 443 Browser https://myi HTTP:443 Encrypted Server (Reverse Proxy) • HTTP 443 documented procedure – Web GUI (2001 port) • Copy the reverse proxy lines into your new 443 instance – ProxyPass / HTTP:8000 – ProxyPassReverse / Server • Change PASE Apache PHP • Allow from all Module httpd.conf: – To Allow from • Allow from (localhost) Higher security
  22. 22. “Reverse Proxy” HTTP Server • Improves performance – Can cache static documents in memory I5_COMD – Can aid with balancing requests to *PGM, *SRVPGM a set of HTTP servers • Improves security CMD, ... – Can control access at the front door HTTP:89 – Can keep server in DMZ separate Server from internal network (Reverse Proxy) IFS – Hides the content server environment /www/zendcore – Can log activity F /usr/local/Zend I R HTTP:80 E Server W (Reverse Proxy) HTTP:8000 A Server DB2 UDB DMZ System L PHP L Module
  23. 23. Tip: PASE Apache prefork start/stop • Good PASE Apache settings • Keep the same – <IfModule prefork.c> – StartServers == MinSpareServers • StartServers 5 – MaxSpareServers == MaxClients • MinSpareServers 5 • Leave as zero or very high count • MaxSpareServers 25 – MaxRequestsPerChild 0 • MaxClients 25 • Never end worker job • MaxRequestsPerChild 0 – </IfModule> HTTP:8000 HTTP:8000 HTTP:8000Server HTTP:8000 Server HTTP:89 HTTP:8000Server HTTP:8000 Server Server Server Server (Reverse Proxy) Avoid PASE Apache bad prefork settings. The machine will prefork to “death”!
  24. 24. Tip: Apache “chroot” • Apache security consultants may recommend chroot to a new directory that can not access other commands on the system. • This approach is not recommended for PASE Apache – The qsys file system will no longer be accessible • PHP interoperability with ILE becomes increasingly difficult – The /QOpenSys file system contains PASE “shared binaries” used by Apache • Chroot below /QOpenSys may be the only way to run without “difficult” copy of runtime for your PASE Apache engine Apache chroot not recommended, (security to failure)!
  25. 25. php.ini configuration /usr/local/Zend/Core/etc/php.ini
  26. 26. php.ini Settings • safe_mode = On/Off – Zend Core default: safe_mode = Off – By enabling safe_mode parameter, PHP scripts are able to access files only when their owner is the owner of the PHP scripts. This is one of the most important security mechanisms built into the PHP. Effectively counteracts unauthorized attempts to access system files and adds many restrictions that make unauthorized access more difficult. • safe_mode_gid = On/Off – Zend Core default: safe_mode_gid = Off – When safe_mode is turned on and safe_mode_gid is turned off, PHP scripts are able to access files not only when UIDs are the same, but also when the group of the owner of the PHP script is the same as the group of the owner of the file. – Utility concerns: • <?php echo shell_exec(“PASE utility steal system”); ?> • <?php echo `system ('call cmd steal from system')`; ?>
  27. 27. php.ini Settings • open_basedir = directory[:...] – Zend Core default: not active (comment only in php.ini) – When the open_basedir parameter is enabled, PHP will be able to access only those files, which are placed in the specified directories (and subdirectories). • safe_mode_exec_dir = directory[:...] – Zend Core default: safe_mode_exec_dir = – When safe_mode is turned on, system(), exec() and other functions that execute system programs will refuse to start those programs, if they are not placed in the specified directory. – More utility concerns: • <?php echo $_POST('textFromEvilUseStealFromSystem');?> – Where HTML form data (textarea) was ... » $_POST('textFromEvilUseStealFromSystem') = » “shell_exec('system('do something bad')')”;
  28. 28. php.ini Settings • display_errors = On/Off – Zend Core default: display_errors = Off – If the display_errors parameter is turned off, PHP errors and warnings are not being displayed. Because such warnings often reveal precious information like path names, SQL queries etc., it is strongly recommended to turn this parameter off on production servers Do not turn display_errors On (default off), instead check /usr/local/Zend/Core/logs/php_error_log
  29. 29. php.ini Settings • log_errors = On – Zend Core default: log_errors = On – When log_errors is turned on, all the warnings and errors are logged into the file that is specified by the error_log parameter. If this file is not accessible, information about warnings and errors are logged by the Apache server. • error_log = filename – Zend Core default: error_log = /usr/local/Zend/Core/logs/php_error_log – This parameter specifies the name of the file, which will be used to store information about warnings and errors (attention: this file must be writeable by the user or group apache). Do not turn display_errors On (default off), error_log = /usr/local/Zend/Core/logs/php_error_log
  30. 30. php.ini Settings • expose_php = On/Off – Zend Core default: expose_php = On – Turning off the "expose_php" parameter causes that PHP will not disclose information about itself in HTTP headers that are being sent to clients in responses to web requests. PHP security by obscurity.
  31. 31. php.ini Settings • .register_globals = On/Off – Zend Core default: register_globals = Off – When the register_globals parameter is turned on, all the EGPCS (Environment, GET, POST, Cookie and Server) variables are automatically registered as global variables. Because it can pose a serious security threat, it is strongly recommended to turn this parameter off (starting from the PHP version 4.2.0, this parameter is turned off by default) // need a "register" global variable? gpost(); $gvar = "Hi"; echo "$gvar {$_POST['gvar']} {$GLOBALS['gvar']}"; function gpost($var) { if(!array_key_exists($var,$_POST)) $_POST[$var]=''; $GLOBALS[$var]=&$_POST[$var]; }
  32. 32. PHP programming /www/zendcore/htdocs/*
  33. 33. Programming APIs • i5_*() APIs • db2_*() APIs – Connect – Connect – CMD call – Results – PGM/SRVPGM call – Commit/Rollback – SQL access – Fetch – Native file access – Statement – Data areas / queues – Stored procedure call – User space – Meta Data – Print/Spool • Column – Job logs • Table – Active jobs • Field • Info – Object list Files or programs with PUBLIC *USE or *ALL, hacker's will have an easier job!
  34. 34. PHP general (information abounds) • Most important rule: never trust user input – Always check user input HTML forms – Always check input to SQL • There are many sites that explain PHP security practices that you can read to “know your enemy” – – php.ini settings (previous section) – Don't use PHP eval on user data • <?php eval $_POST('HackerDelight'); ?> – Don't allow user to specify PHP include names • http://myi.php” • <?php include($_GET['include']); ?> – Don't use include names that can be read by URL (.inc, etc.) • https://myi5/ – Don't allow user to SQL inject your database (db2 section) • db2_exec($_POST(“DropSchemaPayroll;...”');
  35. 35. Toolkit - i5_(p)connect() • i5_pconnect(Server, User, Password [, array Options]) – Server – “”, “localhost” or “” – User - “”, or “uid” i5_pconnect(“”,””,””) • “” - NOBODY profile EASYCOM – Password - “” or “password” HTTP:8000 SRVPGM – Options – Server EASYCOM PGM / CMD • I5_OPTIONS_PRIVATE_CONNECTION SRVPGM EASYCOM PGM / CMD • Return: SRVPGM – IBM i connection HTTP:8000 PGM / CMD – or false on failure Server • i5_pconnect(“”,””,””) – Fewer EASYCOM jobs EASYCOM HTTP:8000 SRVPGM Server PGM / CMD (PRIVATE) Use pconnect over connect avoid start/stop job stress!
  36. 36. ibm_db2 - db2_(p)connect() • db2_pconnect(Database, User, Password [, array Options] ) – Database - “”, “*LOCAL”, db2_pconnect(“*LOCAL”,”NOBODY”,””) • “IASP”, “” – User - QSQSRVR • “”, “NOBODY”, “SOMEUSER” (NOBODY) QSQSRVR – Password - “”, “PASSWORD” HTTP:8000 (NOBODY) • Return: QSQSRVR Server (NOBODY) – IBM i DB2 connection – or false on failure HTTP:8000 • db2_pconnect(“”,””,””) Server • No QSQSRV jobs • db2_pconnect(...,”*NOBODY,””) HTTP:8000 DB2 UDB • Shared QSQSRV jobs Server db2_pconnect(“”,””,””) No “click” route, so do not commit across “clicks”!
  37. 37. i5_pconnect(“localhost”,”uid”,”pwd” Apache “stateless” ... ) EASYCOM EASYCOM EASYCOM HTTP:89 UID:UID:UID: FRED UID: FRED FRED FRED Browser HTTP:8000 myi:89 Server Server HTTP:89 (Reverse Proxy) EASYCOM Browser Server (private) HTTP:89 (Reverse Proxy) myi:89 UID: TOM Server (Reverse Proxy) HTTP:8000 db2_pconnect(“”,”uid”,”pwd”) QTMHHTTP Server DB2 QSQSRVR QSQSRVR QSQSRVR Browser FRED HTTP:8000 UID:UID: FRED FRED UID:UID: JEN JEN myi:8000 TOM Server Browser JEN NOBODY QSQSRVR DB2 myi:8000 NOGROUP QSQSRVR LIZA UID: TOM UID: Liza UID: LIZA ... no “click” has a consistent route (TOM i5 private)
  38. 38. Connect *.inc best intentions, terrible results ... /www/zendcore/htdocs/ <?php function db2ConnPayroll() { return db2_pconnect(“*LOCAL”,”PAY”,”RGFJ183G”); } function i5ConnectCreditCards() { return i5_pconnect(“localhost”,”CREDIT”,”FDRS453Y”); } ?> • Browser http://myi:8000/ – Up pops the source code for, because “*.inc” is just a file not a PHP program – “You've been hacked!” • Instead use ... – /www/zendcore/htdocs/ • Also ... /www/zendcore/htdocs/* – PUBLIC *EXCLUDE
  39. 39. Better connect Apache env vars ... /usr/local/Zend/apache2/conf/httpd.conf # Password PC should be encrypted (MCrypt) SetEnv UC CREDIT SetEnv PC FDRS453Y /www/zendcore/htdocs/ <?php $cc= $_SERVER['UC']; $pc = $_SERVER['PC']; function i5ConnectCreditCards() { global $cc,$pc; return i5_pconnect(“localhost”,$cc,$pc); } ?> • /usr/local/Zend/apache2/conf/httpd.conf – VERY limited access and PUBLIC *EXCLUDE – Include conf/password.conf • /www/zendcore/htdocs/ – For better security add encrypt / decrypt for $_SERVER['PC'] • See PECL extension MCrypt
  40. 40. db2_pconnect and library list ... $uid= $_SERVER['DB2UID']; $pwd = $_SERVER['DB2PWD']; $opt=array(“i5_naming”=>DB2_I5_NAMING_ON); // who are you? if (isset($_SESSION['bigwig'])) array_push($opt, array(“i5_libl”=>'BIGDEAL LILDEAL”)); else array_push($opt, array(“i5_libl”=>”LILDEAL”)); $con=db2_pconnect(“*LOCAL”,$uid,$pwd,$opt); // access the correct data $result = $db2_exec($con, “select * from accounts”); – “i5_libl”=>”BIGDEAL LILDEAL” • call qsys2.qcmdexc('cmd',len) • CHGLIBL LIBL(BIGDEAL LILDEAL) CURLIB(BIGDEAL) – Query known based on $_SESSION['bigwig'] What if our script dies during a BIGDEAL library list query (or times out)? Hopefully, no other PHP script has “select * from accounts”
  41. 41. i5_pconnect and library list ... $uid= $_SERVER['DB2UID']; $pwd = $_SERVER['DB2PWD']; $conn = i5_pconnect("localhost", $uid, $pwd); if (isset($_SESSION['bigwig'])) { i5_command("chglibl",array("libl"=>"BIGDEAL LILDEAL"),array(),$conn); } else { i5_command("chglibl",array("libl"=>"LILDEAL"),array(),$conn); } – “libl”=>”BIGDEAL LILDEAL” • CHGLIBL – Query known based on $_SESSION['bigwig'] What if our script dies during a BIGDEAL library list query (or times out)? Hopefully, no other PHP script has “select * from accounts”
  42. 42. “i5_naming”=> choice/problem ... for ($i=1;$i<21;$i++) { $modulus = $i % 2; if (!$modulus) { $opt=array("i5_naming"=>DB2_I5_NAMING_ON, "i5_libl"=>"BIGDEAL"); $conn = db2_pconnect("*LOCAL", "DB2", "SECRET", $opt); } else { $opt=array("i5_naming"=>DB2_I5_NAMING_OFF, "i5_lib"=>"LILDEAL"); $conn = db2_pconnect("*LOCAL", "DB2", "SECRET", $opt); } • Do not attempt to mix naming in the same profile – "i5_naming"=>DB2_I5_NAMING_ON (lib/table) – "i5_naming"=>DB2_I5_NAMING_OFF (lib.table) • Use separate profiles for each naming – db2_pconnect("*LOCAL", "DB2NATIVE", "SECRET", $opt); – db2_pconnect("*LOCAL", "DB2SQL", "SECRET", $opt);
  43. 43. Use db2_prepare/db2_execute, (and i5_prepare/i5_execute) // db2_exec is unsafe ... $statement = "select email, password, access from eaccounts where email='{$_POST['email']}' and password='{$_POST['password']}'"; $stmt = db2_exec($conn, $statement); // db2_prepare / db2_execute is safer ... $userData = array($_POST['email'], $_POST['password']); $statement = "select email, password, access from eaccounts where email='?' and password='?'"; $stmt = db2_prepare($conn, $statement); $isok = db2_execute($stmt, $userData); // db2_exec is hacked by “' or 1=1 --” and the first row returns (CTO's record) $row = db2_fetch_array($stmt); • Hacked by single-line comment delimiter (--). – $_POST['email'] = "' or 1=1 --"; – $_POST['password'] = ""; • select email, password, access from eaccounts where email='' or 1=1 --' and password='' • Let DB2 do basic analysis on the ? parameter markers to help avoid SQL injection attack (i5_query has inject detect)
  44. 44. Tip: PHP/DB2 with 65535 • Issue: PHP scripts getting “junk” back from their DB2 SQL queries. Root problem is often QCCSID setting 65535 (binary default from manufacturing) • Change CCSID before starting Apache – 0) signon as QSECOFR – 1) go zendcore/zcmenu -> stop apache – 2) CHGJOB LANGID(ENU) CNTRYID(US) CCSID(37) – 3) go zendcore/zcmenu -> start apache PHP/DB2 does not work well with the default 65535 (binary) CCSID setting. Most PHP applications experience what appears to be junk returning in SQL queries (VARCHAR, CHAR, etc.). Change your CCSID to something other than 65535 and restart the Zend Core Apache.
  45. 45. Tip: DB2 – Schema (info) … • On DB2 UDB for iSeries, a schema is used to group related database objects. A DB2 UDB for iSeries schema is actually a collection of DB2 objects and OS/400 objects. When the CREATE SCHEMA statement is executed, the following objects are created: – OS/400 library – OS/400 journal and journal receiver – DB2 views containing schema-wide catalog • This collection of objects in the schema provides the container for storing related DB2 objects and the journal objects needed for enabling recovery of database changes to these DB2 objects. Use schemas (libraries), created with the SQL statement CREATE SCHEMA over CRTLIB to enable journaling. The ibm_db2 commit APIs will not function without journal enabled in the schema (library). In addition, some ibm_db2 BLOB/CLOB scenarios require journal enabled.
  46. 46. MySql quick management • PhpMyAdmin – Manage MySql from the web – • Privileges tab – users/access rights • Manage databases, tables, etc. • MySql GUI tools client / server) – Configurations secure, tunnel, etc. •,249779,249779 • Directory – Zend • /usr/local/mysql – Upgrades 5.1 recommend • /QopenSys/usr/local
  47. 47. Misc • DB2 auditing – –,289142,sid3_gci1189820,00.html • Tango/04 • PCI Apache PTFs – V5R4 - SF99114-20 SI35761, SI35762 Apache 2.0.63 – V6R1 - SF99115-9 SI35767, SI35764, SI35768 Apache 2.2.11 – Zend Core 2.6.1
  48. 48. Trademarks and Disclaimers 8 IBM Corporation 1994-2006. All rights reserved. References in this document to IBM products or services do not imply that IBM intends to make them available in every country. The following terms are trademarks of International Business Machines Corporation in the United States, other countries, or both: AS/400 e-business on demand IBM i AS/400e IBM OS/400 eServer IBM (logo) System i5 iSeries ZendCore Rational is a trademark of International Business Machines Corporation and Rational Software Corporation in the United States, other countries, or both. Intel, Intel Logo, Intel Inside, Intel Inside logo, Intel Centrino, Intel Centrino logo, Celeron, Intel Xeon, Intel SpeedStep, Itanium, and Pentium are trademarks or registered trademarks of Intel Corporation or its subsidiaries in the United States and other countries. Linux is a trademark of Linus Torvalds in the United States, other countries, or both. Microsoft, Windows, Windows NT, and the Windows logo are trademarks of Microsoft Corporation in the United States, other countries, or both. UNIX is a registered trademark of The Open Group in the United States and other countries. Java and all Java-based trademarks are trademarks of Sun Microsystems, Inc. in the United States, other countries, or both. Other company, product or service names may be trademarks or service marks of others. Information is provided "AS IS" without warranty of any kind. All customer examples described are presented as illustrations of how those customers have used IBM products and the results they may have achieved. Actual environmental costs and performance characteristics may vary by customer. Information concerning non-IBM products was obtained from a supplier of these products, published announcement material, or other publicly available sources and does not constitute an endorsement of such products by IBM. Sources for non-IBM list prices and performance numbers are taken from publicly available information, including vendor announcements and vendor worldwide homepages. IBM has not tested these products and cannot confirm the accuracy of performance, capability, or any other claims related to non-IBM products. Questions on the capability of non-IBM products should be addressed to the supplier of those products. All statements regarding IBM future direction and intent are subject to change or withdrawal without notice, and represent goals and objectives only. Contact your local IBM office or IBM authorized reseller for the full text of the specific Statement of Direction. Some information addresses anticipated future capabilities. Such information is not intended as a definitive statement of a commitment to specific levels of performance, function or delivery schedules with respect to any future products. Such commitments are only made in IBM product announcements. The information is presented here to communicate IBM's current investment and development activities as a good faith effort to help with our customers' future planning. Performance is based on measurements and projections using standard IBM benchmarks in a controlled environment. The actual throughput or performance that any user will experience will vary depending upon considerations such as the amount of multiprogramming in the user's job stream, the I/O configuration, the storage configuration, and the workload processed. Therefore, no assurance can be given that an individual user will achieve throughput or performance improvements equivalent to the ratios stated here.