RPGIV @ Work

A unique site for RPG and System i Lovers

Welcome!

Hi, this site will provide all what you need in System i and RPG developments.

My Name is Chamara Withanachchi, System i Expert and RPG Developer. And in the field for last 11 years.

I hope you will find lot of valuable information from this site

Blog - Content Section Layout
Create a IFS folder
User Rating: / 0
Written by Admin (Chamara)   
Sep 08, 2010 at 12:27 AM
      *                                         owner authority
     D S_IRUSR         C                   256
     D S_IWUSR         C                   128
     D S_IXUSR         C                   64
     D S_IRWXU         C                   448
      *                                         group authority
     D S_IRGRP         C                   32
     D S_IWGRP         C                   16
     D S_IXGRP         C                   8
     D S_IRWXG         C                   56
      *                                         other people
     D S_IROTH         C                   4
     D S_IWOTH         C                   2
     D S_IXOTH         C                   1
     D S_IRWXO         C                   7
      *                                         special modes:
      *                                         restrict rename/unlink
     D S_ISVTX         C                    512
      *                                         Set effective GID
     D S_ISGID         C                   1024
      *                                         Set effective UID
     D S_ISUID         C                   2048


     C                   eval      path = '''' + '/myIFS/newFolder'
      * check for the folder in IFS
     C                   eval      rtnCode =  chkPathAvail(path)
     C                   if        rtnCode <> '0'
      * Create the folder in IFS
     C                   callp     crtFolder(path)
     C                   endif

      *--------------------------------------------------------------------
      * Subprocedure to create folder
      *--------------------------------------------------------------------
     P crtFolder       B

     D crtFolder       pi
     D  ifsFolder                    30a

     D mkdir           PR            10I 0 ExtProc('mkdir')
     D   path                          *   Value options(*string)
     D   mode                        10U 0 Value

      /Free

           mkdir(ifsFolder : S_IRUSR +
                             S_IWUSR +
                             S_IXUSR +
                             S_IRGRP +
                             S_IWGRP +
                             S_IXGRP +
                             S_IROTH +
                             S_IXGRP);

      /End-Free

     P                 E
Write Comment (0 comments)
QAUDJRN Journal Entry Types
User Rating: / 0
Written by Admin (Chamara)   
Sep 07, 2010 at 12:03 AM
Entry type   Description 
AD 	Auditing changes 
AF 	Authority failure 
AP 	Obtaining adopted authority 
AU 	Attribute changes 
CA 	Authority changes 
CD 	Command string audit 
CO 	Create object 
CP 	User profile changed, created, or restored 
CQ 	Change of *CRQD object 
CU 	Cluster Operations 
CV 	Connection verification 
CY 	Cryptographic Configuration 
DI 	Directory Server 
DO 	Delete object 
DS 	DST security password reset 
EV 	System environment variables 
GR 	Generic record 
GS 	Socket description was given to another job 
IM 	Intrusion monitor 
IP 	Interprocess Communication 
IR 	IP Rules Actions 
IS 	Internet security management 
JD 	Change to user parameter of a job description 
JS 	Actions that affect jobs 
KF 	Key ring file 
LD 	Link, unlink, or look up directory entry 
ML 	Office services mail actions 
NA 	Network attribute changed 
ND 	APPN directory search filter violation 
NE 	APPN end point filter violation 
OM 	Object move or rename 
OR 	Object restore 
OW 	Object ownership changed 
O1 	(Optical Access) Single File or Directory 
O2 	(Optical Access) Dual File or Directory 
O3 	(Optical Access) Volume 
PA 	Program changed to adopt authority 
PG 	Change of an object’s primary group 
PO 	Printed output 
PS 	Profile swap 
PW 	Invalid password 
RA 	Authority change during restore 
RJ 	Restoring job description with user profile specified 
RO 	Change of object owner during restore 
RP 	Restoring adopted authority program 
RQ 	Restoring a *CRQD object 
RU 	Restoring user profile authority 
RZ 	Changing a primary group during restore 
SD 	Changes to system distribution directory 
SE 	Subsystem routing entry changed 
SF 	Actions to spooled files 
SG 	Asynchronous Signals 
SK 	Secure sockets connections 
SM 	Systems management changes 
SO 	Server security user information actions 
ST 	Use of service tools 
SV 	System value changed 
VA 	Changing an access control list 
VC 	Starting or ending a connection 
VF 	Closing server files 
VL 	Account limit  exceeded 
VN 	Logging on and off the network 
VO 	Validation list actions 
VP 	Network password error 
VR 	Network resource access 
VS 	Starting or ending a server session 
VU 	Changing a network profile 
VV 	Changing service status 
X0 	Network Authentication 
X1 	Identify Token 
XD 	Directory server extension 
YC 	DLO object accessed (change) 
YR 	DLO object accessed (read) 
ZC 	Object accessed (change) 
ZR 	Object accessed (read) 
Calling IBM iSeries RPG Programs with API Calls
User Rating: / 0
Written by Admin (Chamara)   
Sep 03, 2010 at 02:58 AM

The first thing you will need to do is make sure you have the latest version of IBM Client Access (V5R3 or later) installed an make sure that you install the optional programmers toolkit.


Next, you will need to add a reference to the CWBX library from your application. You can do this from the project menu and select "Add Reference". You need to browse to "C:\Program Files\IBM\Client Access\Shared\cwbx.dll". This will give you access to the IBM API's within the cwbx namespace. You can add cwbx to you using statements if you wish.


You need a program that accepts parameters in and out.


I'm going to create a console application which calls an RPG program and returns a value to the user. This example is very basic and does not perform much in the way of error handling.


using System;
using System.Collections.Generic;
using System.Text;
using cwbx;
 
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string result = string.Empty;
 
            StringConverter stringConverter = new StringConverterClass();
 
            // Define an AS400 system and connect to it
            AS400System system = new AS400System();
            system.Define("AS400");
            system.UserID = "USERNAME";
            system.Password = "PASSWORD";
            system.IPAddress = "127.0.0.1";
            system.Connect(cwbcoServiceEnum.cwbcoServiceRemoteCmd);
 
            // Check the connection
            if (system.IsConnected(cwbcoServiceEnum.cwbcoServiceRemoteCmd) == 1)
            {
                // Create a program object and link to a system                
                cwbx.Program program = new cwbx.Program();
                program.LibraryName = "LIBRARY";
                program.ProgramName = "RPGPROG";
                program.system = system;
 
                // Sample parameter data
                string param = "Example";
                int paramLength = 15; // Will be defined in the RGP program, so check with the programmer.
 
                // Create a collection of parameters associated with the program
                ProgramParameters parameters = new ProgramParameters();
                parameters.Append("in", cwbrcParameterTypeEnum.cwbrcInout, paramLength);
                parameters.Append("out", cwbrcParameterTypeEnum.cwbrcInout, paramLength);
                parameters["in"].Value = stringConverter.ToBytes(param.PadRight(paramLength, ' '));
 
                // Finally call the program 
                try
                {
                    program.Call(parameters);
                }
                catch (Exception ex)
                {
                    if (system.Errors.Count > 0)
                    {
                        foreach (cwbx.Error error in as400.Errors)
                        {
                            Console.WriteLine(error.Text);
                        }
                    }
 
                    if (program.Errors.Count > 0)
                    {
                        foreach (cwbx.Error error in program.Errors)
                        {
                            Console.WriteLine(error.Text);
                        }
                    }
                }
 
                result = stringConverter.FromBytes(parameters["out"].Value);
            }
 
            system.Disconnect(cwbcoServiceEnum.cwbcoServiceAll);
            Console.WriteLine(result);
            Console.ReadKey();
        }
    }
}

While this program does work, I found the performance very slow if you are using multiple calls. It takes an age to create a new AS400System object and connect, and it takes a while for the stringConverter to convert a string to a EBCDIC byte array.


If a program falls over on the AS400 for whatever reason, the exception message contained within Ex.Message will contain the AS400 error code and message, so you can also use that to trap errors. For example, ex.Message may contain "CPA3138 – Member BLAH file BLAHBLAH at maximum size." which you can handle.


Here is my solution to the performance issues surrounding the stringConverter class. You can use this in place of stringConverter to save seconds off parameter string conversion times.


/// <summary>
/// Convert an IBM EBCDIC string into ASCII
/// </summary>
/// <param name="strEBCDICString">IBM AS400 EBCDIC string</param>
/// <returns>ASCII String</returns>
public static string ConvertEBCDICtoASCII(byte[] strEBCDICString)
{
    StringBuilder sb = new StringBuilder();
    char newc = '\0';
 
    strEBCDICString = TrimByteArray(strEBCDICString);
 
    for (int i = 0; i < strEBCDICString.Length; i++)
    {
        if (strEBCDICString[i] != '\0')
        {
            newc = Convert.ToChar(e2a[(int)strEBCDICString[i]]);
            sb.Append(newc);
        }
    }
    string result = sb.ToString();
    sb = null;
 
    return result;
}
 
/// <summary>
/// Convert an ASCII string to IBM EBCDIC
/// </summary>
/// <param name="strASCIIString">The ASCII string to convert</param>
/// <returns>IBM EBCDIC array</returns>
public static byte[] ConvertASCIItoEBCDIC(string strASCIIString)
{
    UTF8Encoding encoding = new UTF8Encoding();
    byte[] result = encoding.GetBytes(strASCIIString);
 
    for (int i = 0; i < result.Length; i++)
    {
        result[i] = a2e[(int)result[i]];
    }
 
    return result;
}
 
/// <summary>
/// Character lookup for EBCDIC ASCII Conversion
/// </summary>
private static int[] e2a = new int[256]{
0, 1, 2, 3,156, 9,134,127,151,141,142, 11, 12, 13, 14, 15,
16, 17, 18, 19,157,133, 8,135, 24, 25,146,143, 28, 29, 30, 31,
128,129,130,131,132, 10, 23, 27,136,137,138,139,140, 5, 6, 7,
144,145, 22,147,148,149,150, 4,152,153,154,155, 20, 21,158, 26,
32,160,161,162,163,164,165,166,167,168, 91, 46, 60, 40, 43, 33,
38,169,170,171,172,173,174,175,176,177, 93, 36, 42, 41, 59, 94,
45, 47,178,179,180,181,182,183,184,185,124, 44, 37, 95, 62, 63,
186,187,188,189,190,191,192,193,194, 96, 58, 35, 64, 39, 61, 34,
195, 97, 98, 99,100,101,102,103,104,105,196,197,198,199,200,201,
202,106,107,108,109,110,111,112,113,114,203,204,205,206,207,208,
209,126,115,116,117,118,119,120,121,122,210,211,212,213,214,215,
216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,
123, 65, 66, 67, 68, 69, 70, 71, 72, 73,232,233,234,235,236,237,
125, 74, 75, 76, 77, 78, 79, 80, 81, 82,238,239,240,241,242,243,
92,159, 83, 84, 85, 86, 87, 88, 89, 90,244,245,246,247,248,249,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57,250,251,252,253,254,255
};
 
/// <summary>
/// Character lookup for EBCDIC ASCII Conversion
/// </summary>
private static byte[] a2e = new byte[256]{
0, 1, 2, 3, 55, 45, 46, 47, 22, 5, 37, 11, 12, 13, 14, 15,
16, 17, 18, 19, 60, 61, 50, 38, 24, 25, 63, 39, 28, 29, 30, 31,
64, 79,127,123, 91,108, 80,125, 77, 93, 92, 78,107, 96, 75, 97,
240,241,242,243,244,245,246,247,248,249,122, 94, 76,126,110,111,
124,193,194,195,196,197,198,199,200,201,209,210,211,212,213,214,
215,216,217,226,227,228,229,230,231,232,233, 74,224, 90, 95,109,
121,129,130,131,132,133,134,135,136,137,145,146,147,148,149,150,
151,152,153,162,163,164,165,166,167,168,169,192,106,208,161, 7,
32, 33, 34, 35, 36, 21, 6, 23, 40, 41, 42, 43, 44, 9, 10, 27,
48, 49, 26, 51, 52, 53, 54, 8, 56, 57, 58, 59, 4, 20, 62,225,
65, 66, 67, 68, 69, 70, 71, 72, 73, 81, 82, 83, 84, 85, 86, 87,
88, 89, 98, 99,100,101,102,103,104,105,112,113,114,115,116,117,
118,119,120,128,138,139,140,141,142,143,144,154,155,156,157,158,
159,160,170,171,172,173,174,175,176,177,178,179,180,181,182,183,
184,185,186,187,188,189,190,191,202,203,204,205,206,207,218,219,
220,221,222,223,234,235,236,237,238,239,250,251,252,253,254,255
};

All this does is simply convert one format to another using a lookup table. Much, much faster than whatever the IBM library is doing. To use it simply replace:

parameters["in"].Value = stringConverter.ToBytes(param.PadRight(paramLength, ' '));

with

parameters["in"].Value = ConvertASCIItoEBCDIC(param.PadRight(paramLength, ' '))

and

result = stringConverter.FromBytes(parameters["out"].Value);

with

result = ConvertEBCDICtoASCII(parameters["out"].Value);

Other performance issues surround the use of the AS400System object. It seems to take around 3-5 seconds to create a new object and connect to the system. There are a few ways around this, but the one I prefer is to use an object factory class or singleton to dispense connections. If you are working on Windows Forms then you can get away with creating a "global" variable to hold the AS400System, while on ASP.Net you can use a pool of objects and a singleton dispenser.

 

User Profile and Password Tricks
User Rating: / 1
Written by Admin (Chamara)   
Sep 01, 2010 at 11:11 PM

1. You can't create a system i user profile name that starts with a number but you can sign on with a user profile name that begins with a number.
In several systems besides i5/OS, administrators can set up user profiles that begin with a number rather than a letter. However, i5/OS has a prohibition against starting a user profile name with a number, but there is a workaround. If you want to synchronize your i5 user profiles with other system IDs that start with a number, you can configure i5 users to also sign on with a user profile name that begins with a number.
It's easy to configure a user profile for numeric sign-on. The process starts by creating a user profile that has the following format:
Qnxxxxxxxx
Where Q equals the letter 'Q', n equals any number between 0 and 9, and xxxxxxxx equals any eight character or less string consisting of letters, numbers, or the special characters @, #, $, or _. Using this naming convention, any of the following user profiles would be valid i5/OS user IDs.

Q1TEST#
Q12345
Q1_2_3_4_5

Either by quirk or design in i5/OS, user profile names configured according to the Qnxxxxxxxx format allow users to sign on to an i5/OS system by using two different user profile names. The actual Qnxxxxxxxx profile name that was created for the user.


The second 2 through 9 characters of the user profile name, the nxxxxxxxx part of the name. For our sample user profiles, this means that a user could sign on to an i5 system by using any of the following user profile names.

Q1TEST# or 1TEST#
Q12345 or 12345
Q1_2_3_4_5 or 1_2_3_4_5

When the user signs on, his job name will always be created and running under the Qnxxxxxxxx name but i5/OS will also accept an alternate user sign-on under the shortened nxxxxxxxx user name. This quirk allows you to fool the user into thinking that they are signing on with a user profile that starts with a number, even though the system is using a user profile that starts with the letter 'Q'. This is a handy trick when you want your users to sign on to different systems with a consistent user profile name that starts with a number.


Better Password Management
User Rating: / 1
Written by Admin (Chamara)   
Sep 01, 2010 at 11:05 PM

Original article by by Joe Hertvik


1. Two system values can prevent your users from using actual words in their passwords
If you want to stop your users from entering passwords that contain complete words that can be easily hacked, try setting on The Require Digit in Password (QPWDRQDDGT) system value. This system value will force the user to enter at one or more digits in their password, forcing them to at least add a number to the end of a common word to make their password harder to guess. To completely eliminate the use of common words as passwords, use the Limit Characters In Password (QPWDLMTCHR) system value. QPWDLMTCHR does what its name implies: it prevents users from using certain letters in a password. So if you use QPWDLMTCHR to ban the use of any vowels ('AEIOUY') in a password, the user cannot designate a complete English word as their password. This technique should also work for passwords on machines that use other language features. Just adjust the restricted characters to match the local dialect. For added security, use both system values and all your user passwords will resemble license plate numbers instead of common dictionary words and phrases.


2. You can use a combination of system values to prevent your users from re-using an old password for several months or years
By changing two system values in connection with each other, you can stop users from re-using an old password for years. The first thing you need to do is to follow best audit practices and force your users to change their passwords every 90 days or less. This is done by setting the Password Expiration Interval (QPWDEXPITV) system value to 90 days, which is the number of days the current password can be used before it expires. Then set the Password reuse cycle (QPWDRQDDIF) system value, also known as Duplicate password control, to 10 cycles or more. By doing this, the user will be forced to change their password every 90 days, BUT they won't be able to reuse their original password until they've changed their password 10 times. This means that a user signing on to an i/OS system configured this way won't have the opportunity to reuse a password for about 2.5 years (90-day password expiration * 10 reuse cycles = 900 days =~2.465 years). So if you set your system values right, you can prevent your users from using the exact same password again for a very long time.


3. You can change password configurations graphically
The good news is that you don't have to change your password system values on the green screen, making one change at a time without understanding how all the different values fit together. In i/OS V5R4Mx, you can use iSeries Navigator (OpsNav) to change password settings. You open the OpsNav Password System Values screen by clicking on the Configuration and Service→System Values→Password node under your target system in OpsNav.


4. Passphrases can be used instead of passwords
Your i/OS box isn't limited to 10-character passwords. You can easily change your password architecture to accept up to 128-character passphrases that can include special characters, embedded blanks, and upper- and lower-case characters.


5. When using higher password levels, i/OS password are case sensitive
If you change your Password Level (QPWDLVL) system value to '2' or '3' to implement passphrases or for another reason, be aware that your passwords will now become case sensitive. Case sensitivity doesn't matter with lower security levels, but it can cause problems when you change QPWDLVL to '2' or '3', especially with companion servers. For example, let's suppose you change QPWDLVL to '2' and you have a companion server that logs on to your machine with a user profile of IUSER and a password of 'PASSWORD'. When QPWDLVL was set to '0' or '1', i/OS didn't worry about case and an automated sign-on with capital letters in its password always worked. But after you set QPWDLVL to '2', i/OS will now start checking the case sensitivity of the enter password ('PASSWORD') with the case sensitivity of the password stored on your i/OS machine ('password'). If the passed-in password and the i/OS password for IUSER do not reconcile, the operating system will refuse the connection attempt even though the upper-case password was acceptable before the change. Watch out for this.


6. i/OS passwords can start with a number
Here's an operating system paradox for you. i/OS users cannot change their password to a value starting with a number, BUT in certain situations i/OS users can sign on with a password that starts with a number. Confused? There's a quirk in i/OS that if a user changes his password to start with the letter 'Q' followed by a number (e.g., Q12345), that user will be able to sign on by either using his stated password of Q12345 or by using an alternate password of 12345. Strange, but true.


<< Start < Previous 1 2 3 4 5 6 7 8 9 10 Next > End >>

Results 1 - 10 of 422