In the world of Linux, SSH is extremely popular. It provides the ability to log on to other computers (similar to Telnet), the ability to run commands on other computers from a script (similar to the RUNRMTCMD command in i5/OS), the ability to copy files over a network (like CRTDUPOBJ over a network), the ability to tunnel network traffic (like a very simple VPN), and a file transfer utility (like FTP).
No matter which of these functions you use, SSH protects the network transmissions with high-quality encryption and private key authentication. And it can be run both interactively and from a script or program.
Oh yeah, did I mention that it's available free of charge?
Starting with V5R3, IBM makes OpenSSH available for i5/OS running under PASE. In this article, I talk about the OpenSSH toolkit with a focus on how you might use it from i5/OS programs.
The OpenSSH toolkit is the SSH implementation that's available for i5/OS. It's the most popular SSH implementation on the market today. A survey done in November 2005 estimated that more than 85 percent of the SSH servers on the Internet are using OpenSSH. The fact that i5/OS can run this mainstream implementation of SSH is good news because it means that i5/OS file transfers that use SSH will interoperate properly with all of the other systems out there.
On the other hand, if you're not used to the way things are done on Unix systems, you might find OpenSSH a little cumbersome to use, since it wasn't designed for the CL command interface that you're probably used to.
Running OpenSSH on i5/OS requires the following:
i5/OS V5R3M0 or later.
TCP/IP set up and working.
Name resolution (the i5/OS DNS Resolver) should be configured properly.
Portable Application Solutions Environment (PASE) (5722-SS1, opt 33) must be installed.
This is a licensed program that lets you run AIX software under i5/OS. It's included with the CDs you received from IBM when you ordered i5/OS, but may not be installed if you haven't installed it previously.
Like all components of i5/OS, you can install it by typing GO LICPGM and choosing option 11.
IBM Portable Utilities for i5/OS (5733-SC1)
When I ordered i5/OS V5R3, this was not included with the CDs. I had to talk to my IBM Business Partner (the same folks that I called when I ordered i5/OS) to get this licensed program sent to me. It was sent, free of charge.
When I ordered i5/OS V5R4, however, 5733-SC1 was included with the i5/OS CDs. I don't know if that's standard, or not. In any case, if you don't have the CD, call your business partner and have him send you a copy.
Once you've installed PASE and have the media for 5733-SC1, you can install it on your system by typing the following commands:
RSTLICPGM LICPGM(5733SC1) DEV(<em>OPT01</em>) OPTION(1) RSTOBJ(*PGM)
Replace OPT01 in the preceding commands with the name of the optical disk unit that you're using to install 5733-SC1.
Running an SSH Server
On Unix systems, an SSH server is frequently used for interactive logons, in much the manner that we use the Telnet server under i5/OS. It lets terminal emulators connect, sign in, and get a command prompt where interactive commands can be run. However, unlike the i5/OS Telnet server, the SSH one runs in PASE, and therefore gives you a PASE command-line.
SSH's tunnelling support can be used as an alternative to SSL for encrypting 5250 data streams, however, I've found that not too many shops are interested in doing that. They're happy with their SSL!
But, running an SSH server on i5/OS is really valuable as an secure alternative to FTP. Standard FTP isn't encrypted, and therefore has many drawbacks related to security. Although the FTP server in i5/OS is capable of running FTP over SSL, using SSH works better. FTP over SSL is notoriously difficult to get working through a firewall or NAT gateway -- however, SSH doesn't have any problems. As long as the firewall allows port 22 to come through, SSH works great.
Generating Server Keys
If you plan to run SSH as a server application, you need to establish public and private keys for the SSH clients that might connect to your server. These keys are used when a client connects so that the client can (cryptographically) know which server it's connected to. The first time a client connects, it'll download your public key and store it in a database. Subsequent connections will verify that the key hasn't changed so that the client application can be sure it's connected to the right place, and that their connection hasn't been usurped by a mischievous hacker.
The server keys only need to be generated once, immediately after installing OpenSSH.
There are three different types of keys available in SSH, so you'll want to generate server keys for all three of these types. Here are the commands you need to run to generate the keys:
To get a PASE command shell, type the following command:
Change your current directory (analogous to *CURLIB, the current library we're used to in i5/OS) to the one where the OpenSSH configuration is stored by typing:
Generate the keys by typing the following three commands:ssh-keygen -N "" -t rsa1 -f ssh_host_key
ssh-keygen -N "" -t dsa -f ssh_host_dsa_key
ssh-keygen -N "" -t rsa -f ssh_host_rsa_key
Press F3 to exit the PASE shell and return to the regular i5/OS command line.
Starting the OpenSSH Server
The server program for OpenSSH is called "sshd", which stands for "SSH daemon". In Unix terminology, the word "daemon" is synonymous with "server", so when they say SSH daemon, they really mean the SSH server.
To start the server, type the following command:
SBMJOB CMD(CALL QP2SHELL PARM('/QOpenSys/usr/sbin/sshd')) JOB(SSHD) JOBQ(QUSRNOMAX)
To end the SSH server, type the following command:
From that screen, take option 4 next to each of the SSHD jobs in the subsystem, and press enter to end them.
Note: Although the above options work for me, some people prefer to create a dedicated subsystem for SSHD jobs. This is a good idea if you plan to handle a lot of SSH clients connecting to you. IBM has provided instructions on how to do that in Chapter 2 of the Redpaper titled Securing Communications with OpenSSH on IBM i5/OS
At this point, the OpenSSH server should be ready for clients to connect to and use in it's default configuration. The default configuration works very nicely for most shops, however, if you want to change the way the server works, there's a configuration file that you can edit with the following command:
Documentation for the options listed in that file can be found on the OpenSSH web site. Go to the following link, and click "sshd_config" for details:
Once you've changed the configuration, you'll need to stop and restart the SSHD jobs for the changes to take effect.
Using the OpenSSH Client Programs
OpenSSH comes with a bunch of different programs, but these are the main ones that you'll be interested in:
ssh -- The main client program, this is used for interactive logins (like Telnet), running remote commands, and creating tunnels.
scp -- secure copy. This tool is a very simple way to copy files over a network. The syntax is intended to be similar to the Unix cp (copy) command that's used to copy files.
sftp -- secure FTP. Despite the name, this tool does not use the FTP protocol! It uses the SSH protocol, but, it provides a command-line interface very similar to what you see with popular FTP clients.
Establishing Keys for Client Programs
All of the SSH tools were designed to either run interactively or from a Unix shell script. You can use that script support to automate the SSH applications from a CL program, PASE shell script, or even an HLL language (e.g., RPG) if you want to.
One of the basic problems you face in creating a script is this: What do you do with the password? If there's no interactive user, there's nobody to the type the password in. You don't want to hard-code the password into a program or script because of the security ramifications. Anyone who can get their hands on your source code can find out the password! That's not good! The public and private key files were intended to solve this problem.
The idea is that you generate a pair of keys for each user who will be using SSH. The pair consists of a private key (a secret that should never be given to anyone) and a public key that should be installed on the SSH server that you're connecting to. During the connection process, it will verify that the public key on the server matches the private key on the local machine. If they match, then the system will skip the password prompt, and log you in immediately.
So, you generate the keys once for each user and install them, and from that point forward, the logins are automatic. Scripts can connect, run commands, send and receive files, and so forth without any need to type a password.
Don't get me wrong -- it's perfectly possible to use the SSH tools without generating or installing these keys. However, the keys improve security and make scripting much easier, so I recommend that you generate them.
Here are the steps required to generate keys:
Log on to a 5250 session as the userid who will be running the SSH client programs.
Find out the name of the user's home directory by typing the following command, and paging down to where the home directory is displayed on the screen:
Type the following to get an interactive PASE command shell:
If the user's home directory (from the last step) doesn't exist, you'll need to create it. For example, if the home directory is supposed to be /home/klemscot, then type the following:mkdir /home/klemscot
chmod 750 /home/klemscot
Create the public/private key pair:ssh-keygen -t rsa -N ""
When it asks which file to save the key in, just press ENTER to take the default. This step will create a directory named .ssh within the user's home directory, and inside that directory will be two files named id_rsa and id_rsa.pub. These are your private and public key files, respectively.
The id_rsa.pub file from the previous step needs to be transferred to the destination SSH server -- that is, the server you will be connecting to from your SSH client -- and installed in the "authorized_keys" file on that server.
How this file gets installed will depend on the policies put in place by the administrator of the destination SSH server. Sometimes they'll do the initial key setup on that server by e-mailing the public key to the server's administrator. Other times, it'll be transferred using SSH with password authentication, or with an unencrypted file transfer program like FTP.
In any event once the file has been transferred to the server, you'll want to have a .ssh subdirectory off of the user's home directory on the SSH server. You can create the directory and add the key to the authorized_keys file by typing the following commands at a Unix command prompt on the server (which will be the PASE shell if it's an i5/OS server).mkdir /home/<em>my-user-id</em>/.ssh
cat id_rsa.pub >> /home/<em>my-user-id</em>/.ssh/authorized_keys
chmod 600 /home/<em>my-user-id</em>/.ssh/authorized_keys
Establishing the Server as a Known Host
At this point, even if the public keys have been installed properly on the server, the "scp" or "sftp" tools will fail because they don't trust the server.
For example, this is what happens if I try copy a file with the scp tool from an interactive PASE prompt:
Host key verification failed.
This is because the SCP utility (SFTP has the same issue) is designed to only trust servers that are in it's "known_hosts" file. On a Unix system, if you run the SCP or SFTP tool interactively and connect to a host that it's not familiar with, it'll ask the user whether they want to trust the host and add it to the known_hosts file. However, since these tools where created for Unix, they do not recognize a 5250 terminal as an interactive terminal! In the preceding example, SCP thinks I'm running it from a script even though I actually ran it interactively, because it doesn't recognize the 5250 terminal.
The solution is to connect with the 'ssh' tool first to get it to add the server to the known hosts file. To do that, you'll want to type the following command:
In this example, I've told it to connect to the SSH server named "ssh.example.com" as userid "remote-user" (change that to the server name and user id for the server you're logging in to.) Once it connects, it will run the "exit" command on the remote server -- which, on Unix servers, causes you to log off again and ends the connection. The "exit" command on Unix is analogous to SIGNOFF on i5/OS.
Since I'm signing off right away, this connection to the server really doesn't do anything -- except that it'll download the server's key, and if it's unfamiliar, it'll give me the chance to add it to my known_hosts file. When this happens, I'll see the following on the screen:
The authenticity of host 'ssh.example.com (192.168.0.1)' can't be established.
. key fingerprint is DSA.
Are you sure you want to continue connecting (yes/no)?
If I type "yes" and press enter, it'll automatically add this host to my known_hosts file. Once that has been done successfully, I'm able to use tools like "scp" or "sftp" without receiving the "Host key verification failed." error.
What If Interactive Logins Are Disabled?
The preceding information on establishing interactive logins requires that the SSH server lets you log in to run a remote command (in that example, it was the "exit" command). However, some servers are set up for scp access only, or sftp access only and do not allow these interactive logins. Servers like this are rare, but they do exist.
In that situation, you'll have to use the SCP or SFTP utility to download the host's key into the known_hosts file. As I explained in the previous section, that won't work from a 5250 terminal because those utilities won't realize they're running interactively. Fortunately, it's possible to use a different terminal aside from a 5250!
To try that, follow these steps:
Set up the SSH server on your System i, following the steps described earlier in this article.
Download Putty.exe, which is a free SSH client for Windows. Here's a link to the Putty home page:
The only file you need to download is putty.exe. Just download it to your desktop, and double-click it to run it.
Under "host name", put the domain name or IP address of your System i where you just started the PASE server. Make sure SSH is selected and click "Open".
Log in to your System i using the user id and password you typically would use for a 5250 session.
You should now be at a PASE command prompt. From that prompt, type the "scp" or "sftp" command needed to connect to the remote server. Since you're no longer using a 5250 terminal (instead you're using Putty which is a Unix-like terminal) it should give you the same prompt that the "ssh" command gave in my previous example.$ scp test.csv firstname.lastname@example.org:
The authenticity of host 'ssh.example.com (192.168.0.1)' can't be established.
DSA key fingerprint is 68:9d:6e:10:7a:7f:09:d5:21:20:17:4f:e9:1d:fe:92.
Are you sure you want to continue connecting (yes/no)?
When you answer "yes" to this question, it'll add the host to your "known_hosts" file. Subsequent attempts to use "scp" or "sftp" from the 5250 terminal, or from a CL program should now work without any hassle.
Using the SSH Tool
The SSH command can be used to create tunnels between a TCP port on the local computer and a TCP port on the remote one. This can be used as something of a "poor mans VPN", providing a means of encrypting and securing TCP channels over internet connections.
It also provides an interactive login as a unix terminal emulation program -- something that's not often used in an i5/OS environment.
Finally, it can be used to invoke commands on the remote server, similar in concept to RUNRMTCMD, but much, much more secure.
While these are all really nifty features, I have only found a small handful of people in the System i community that are interested in using the SSH tool itself. Just about everyone out there is looking for help with SCP or SFTP. Therefore, I'm not going to spend any more space in this article talking about the SSH tool. Instead, please refer to the documentation on the OpenSSH home page:
Using the SCP Utility
The SCP utility is purely for copying files from one place to another. It's intended to mimic the normal Unix "cp" (copy) utility, except that you can prepend a filename with the name of the server that it should be copied from.
For example, if I want to copy a file named /tmp/test.csv from my local i5/OS system to a remote SSH server, I could type the following:
The first parameter, after the "scp" command itself, is always the original file that you want to copy. The last parameter always identifies the path name of the file or directory of the destination.
The part that says /tmp/test.csv identifies the file on my side of the connection that is to be sent. It is a path name in IFS naming format. Any time you specify a path name (like this one) that does not contain a colon, it is assumed to be on the local machine.
The part that says "email@example.com:" is not an e-mail address. Instead, I'm telling it that I want to copy the file to the "ssh.example.com" server, and that my user name on that server is "klemscot". The server name is always followed by a colon to separate it from the filename. After the colon is the path name where the file will be stored on the server, in this example, it'll be saved under the name /sharedfiles/klement/test.csv on the server.
If you want to receive a file from the server (as opposed to sending it to the server) you simply reverse the order of the parameters.
scp firstname.lastname@example.org:/customers/klement/edidata.txt /tmp/edi.txt
In this example, I'm prefixing the first filename with the hostname, followed by the colon. This tells "scp" that I want to copy from the remote host, since it's the source path name that I've prefixed with a host name. The destination path name , in this example /tmp/edi.txt, indicates the place I'd like to save the file to on my local system.
It's also worth noting that the user id in the "scp" command is optional. If you leave it off, it'll assume that your user id is the same on the remote system as it is on the local system. So if my user name on the local system is scottk, then the following command will log in to ssh.example.com as the user named scottk.
scp ssh.example.com:/customers/klement/edidata.txt /tmp/edi.txt
Similarly, when you're sending a file, you can specify a host name, but omit the path name, if you want to keep the same filename and upload it into the default directory on the server. For example:
You can use these SCP commands in a CL program if you like. To do that, you have to have the CL program call the QP2SHELL API, which is used to invoke a PASE command shell and run a command in that shell. For example:
DCL VAR(&CMD) TYPE(*CHAR) LEN(1000)
CHGVAR VAR(&CMD) VALUE('scp test.csv ssh.example.com:')
CALL PGM(QP2SHELL) PARM('/QOpenSys/usr/bin/sh' '-c' &CMD)
The QP2SHELL API takes the path name of the PASE command shell as it's first parameter, and each subsequent parameter will be passed to that shell. In this case, I've told it to call the program named "sh" that's located in the /QOpenSys/usr/bin directory of the IFS -- this is the default shell in PASE. I'm passing a parameter of -c to that shell, which tells it I want to run a command, and the third parameter contains the PASE command that needs to be run. This is, of course, the "scp" command.
The &CMD variable in the preceding example code can be built an expression if necessary. For example, if the server name, file names, etc were variables, I could concatenate them together in the CHGVAR statement to create the command string that I want PASE to run.
I recommend that you start by figuring out the exact PASE command that you want to run, and try it interactively (through the QP2TERM program) to make sure it works. Once you have the syntax of the command all figured out, then try coding it in your CL program. Trying it interactively makes it much easier to see what errors are occuring.
Once keys are established, the SCP tool is a very simple tool for transferring files over a network. As you can see by my examples, above, it's extremely easy to write a program that transfers a file over a network using SCP.
Using the SFTP Tool
The SCP tool is great -- but it's limited. Although it can copy files over a network, it can't rename them, delete them, list the contents of directories, create directories, and so forth. If you want to do that sort of thing, you need to use the SFTP tool. The user interface for SFTP is designed to look just like the interface for regular FTP, so if you're comfortable using an FTP client, you'll find it easy to adapt to SFTP.
If you're not familiar with FTP, you may be interested in checking out the following article:
FTP for Techies and Programmers
Here I will describe the differences between SFTP and FTP:
SFTP encrypts the connection, and has the option to use key pairs (as described above) instead of passwords for authentication.
SFTP always does everything on TCP port 22, whereas FTP selects a different port for each transfer. This makes SFTP much easier to use through a firewall.
SFTP has no notion of ASCII vs. BINARY file transfers. In normal FTP, this is used to control whether data gets translated from one character set to another or not. In SFTP, no translation is ever done -- therefore SFTP is similar to using BINARY mode in standard FTP.
I recommend that you use tools like CPYTOSTMF, CPYFRMSTMF, CPYTOIMPF, CPYFRMIMPF and QShell to convert your databases to/from ASCII and convert them to the required format. That way, you won't have to worry about ASCII/EBCDIC translations.
SFTP does not have any of the i5/OS specific features like RCMD, LOCSITE, and NAMEFMT. The naming format is always IFS-style. Remote commands aren't run through SFTP (but are run through the SSH utility instead.)
SFTP does not use OVRDBF for scripting. Instead, if you want to use SFTP with a script, you have to put the script in an IFS file and run it with the -b parameter to SFTP.
Scripts in SFTP stop as soon as one of the commands fail. In normal FTP, when a command fails, the script continues with the next command.
For example, if I want to invoke sftp interactively, I could do the following:
This would log me into the ssh.example.com server as user id klemscot. Now I have an FTP-like command prompt where I can use commands like dir, get, put, cd and mkdir, just like I'd use in an FTP session. I can type "help" to get a list of all of the available commands.
Script files for SFTP have to be ASCII files stored in the IFS. To create one, type the following commands:
STRQSH CMD('touch -C 819 /tmp/myscript.sftp')
This creates a new IFS file named /tmp/myscript.sftp, and sets the CCSID of that file to 819, which is ISO-8859-1, a variant of ASCII that's widely used where I live.
- <p>This invokes a green-screen editor -- very similar to SEU -- that I can use to edit my SFTP script.
For example, you could create an SFTP script that contains the following lines:
Now that I've created an SFTP script, I can invoke it as follows:
This tells sftp to run the script as a "batch file". You'll note that there's no user-id or password in the FTP Script. Instead, the user id is specified on the sftp command line. The password isn't used, since the key authentication makes it unnecessary.
Naturally, I can run this script from a CL program instead of a command line, if I want to.
DCL VAR(&CMD) TYPE(*CHAR) LEN(1000)
CHGVAR VAR(&CMD) VALUE('sftp -b /tmp/myscript.sftp +
CALL PGM(QP2SHELL) PARM('/QOpenSys/usr/bin/sh' '-c' &CMD)
Using Password Authentication -- Even for Batch FTP
When talking about digital keys, above, I mentioned that hard-coding a password in a script is a bad idea, and explained why I like public key authentication instead of sending a password. I've also explained that the SCP and SFTP utilities verify that they're being called interactively before allowing password authentication, and require a key when using scripting.
However, sometimes you have to work with a business partner that doesn't give you a choice. Either you use the password authentication that they tell you to use, or you're out of luck.
When you're in a situation like that, there's a workaround. There's a program available for AIX (that can run in PASE on i5/OS) called "expect". Expect is a scripting tool that's designed to look like an interactive terminal to the programs that it calls. That way, it's scripts can call interactive programs, but instead of getting input from the keyboard, the script sends the key strokes to the program.
The Expect utility is free software for AIX that runs under PASE. It requires TCL as a dependency. I searched the web and found TCL and Expect for AIX at the following links:
I downloaded those files to the /tmp directory of the IFS on my System i. To install them, I typed the following commands:
$ cd /tmp
$ uncompress tcl.8.4.9.tar.Z
$ uncompress expect.5.43.tar.Z
$ cd /
$ tar xf /tmp/tcl.8.4.9.tar
$ tar xf /tmp/expect.5.43.tar
Press F3 to exit PASE.
Now that I've installed the tools, I created an Expect script that will control the sftp tool. That Expect script is capable of passing the password, so I don't have to set up keys.
To create the Expect script, I typed the following commands:
STRQSH CMD('chmod +x /tmp/myexpectscript')
Before typing in the script, I hit F15 and changed my stream file EOL option to *LF (the default is *CRLF) to make it more compatible with the way things are done in Unix.
Finally, I typed the following script:
spawn sftp email@example.com
send "put myfile.csv\n"
In this example, the first line (the one that starts with #) tells PASE which shell to run the script under. In this case, I want PASE to run it with the shell named /usr/local/bin/expect.
The "spawn" line tells Expect which program to start up. In this case, it starts up sftp and passes my user id and the name of the server to connect to.
The script then waits for "Password:" to be printed by the SFTP client, and when this does appear, it sends my password ("bigboy" in this example). It then waits for "sftp>" and when that is found, it sends the "put" command, etc.
So, Expect provides a nice way to create a script that can automate SFTP, and send a password for authentication instead of having to use a key pair.
I can invoke the expect program from a CL program using a syntax like this:
CALL QP2SHELL PARM('/usr/local/bin/expect' '-df' +
The following links provide more information about using OpenSSH under i5/OS:
- OpenSSH's documentation on their web site.
- Redpaper: Securing Communications with OpenSSH on IBM i5/OS
- IBM Porting Central page about OpenSSH on i5/OS
- The IFS/File Conversion/File Transfer forum on SystemiNetwork.com provides a great place to ask questions if you're stuck.