Section 12.1 Protecting User Sessions with SSH

   


12.1 Protecting User Sessions with SSH

graphics/fivedangerlevel.gif

SSH is short for Secure SHell. It is a set of programs created by Tatu Ylönen for Linux, UNIX, Windows, MacOS, Java, and VMS that offers secure TCP communications between any two systems regardless of what untrusted systems might be between them as routers or firewalls and regardless of what untrusted systems might be listening (sniffing) on each system's local area network, phone lines, cable modem segment, upstream provider's network, etc. SSH uses thoroughly proven public key encryption techniques. Among SSH's many innovations is its technique of storing only an encrypted version of each person's private key on each system.

This means that even root can see a user's private key or a user's clear text (before the text is sent to the remote system or after it is received and decoded) only by having the special expertise to interpret the system's memory and does so during the conversation. It would require brute force breaking of a user's password protecting the user's private key to otherwise see it under any other circumstances, such as the intruder or rogue doing this when the user under attack is not actively using SSH.

SSH is considered one of the most valuable security tools in existence, and every SysAdmin and user should make maximum use of it. SSH most commonly is used as a secure replacement for telnet, rsh, rcp, and rlogin. The sftp program, a secure FTP, was made part of the SSH suite in early 2000. SSH may be used for secure network X sessions. It may be used for Post Office Protocol (POP) sessions, though SSL seems to be supported by more client-side applications on non-Linux platforms. In fact, SSH may be used as a secure pipe between the two systems (endpoints) for any TCP service. This yields a Virtual Private Network (VPN) tunnel between systems at a very low price (free).

SSH operates by using public key encryption techniques to encrypt each message, send that encrypted message over the network, and then decrypt it on the other side and pass the decrypted message to whatever program is expecting it. SSH offers the three things important to secure communications:

  1. It offers encryption to prevent anyone sniffing the network at either end or anywhere in the middle from seeing the message. This also protects users from IP spoofing, fake routes, and DNS spoofing.

  2. It offers authentication so that each side knows absolutely that it is talking to whom it thinks it is. In other words, each side knows that each message (packet) is getting to the intended destination, is not a rogue, and was not sent by a rogue. This avoids "the Man-in-the-middle attack" where A thinks it is talking to B but really is talking to Man-in-the-middle X who then passes a different message on to B. See "Man-in-the-Middle Attack" on page 257 for a full description of this attack.

  3. It offers integrity. This means that the message gets received by the other side complete and with no alterations possible. It also prevents a "replay" attack, where a session is sniffed and then replayed to cause the same action to be repeated, perhaps the transfer of money or goods.

SSH uses 1024-bit keys so that nobody other than the National Security Agency (NSA) and other spooks could possibly decode a message in fewer than several years and probably in not fewer than many years. Even the NSA and Echelon would have great difficulty in breaking it and certainly would not bother unless you are a spy or terrorist, in which case this book is not intended for you.

What can't SSH do? Because SSH only supports TCP between the two cooperating systems, it will not work for UDP or ICMP messages (though there are VPN solutions built on top of SSH). It will not work for "store and forward" situations such as sending e-mail, where it is not the two cooperating people (the one sending the e-mail and the one reading the e-mail) who have the TCP session. Rather, it is some sendmail program that the sender connects to and some other sendmail (that eventually delivers the e-mail to the reader) that have the TCP session.

The following steps may be followed to get, build, and use SSH2. I discuss the "standard" version from www.ssh.org. There is a competing version that some people might prefer from www.openssh.com (with U.S. download site ftp://thermo.stat.ncsu.edu/pub/openssh/files/).

Although sendmail 8.10 offers some encryption capability, Pretty Good Privacy (PGP) is the time-tested method of protecting e-mail and other "chunks of data" that might sit around for a while on media such as disk files, tapes, floppies, and CD-ROMs, or which hop from one system to another.


Is it generally better to use SSH2 or openssh? The openssh version allows commercial use for free (using the BSD license model). Also, it uses data compression and appears to be well supported too. To use it, however, you first must download and build openssl and zlib (the compression library). Use of openssh in the U.S. might violate RSA's patents (but they expired in September 2000).

SSH2 does prohibit commercial use without paying license fees but does offer sfpd, a secure FTP version in addition to the common features. SSH2 uses Diffie-Hellman key exchange.

Although SSH1 had been less restrictive, it was announced the week of the completion of this book's first edition that people who get SSH1 bug fixes now are forced to accept the more restrictive SSH2 license. This same questionable tactic was taken years ago by AT&T with the UNIX license; most of the major UNIX vendors told them to take a trip to someplace hot.

The openssh implementation supports protocol versions 1.3 and 1.5 and now supports version 2.0.


Although the standard (SSH2) version has few license restrictions that would affect many people using Linux, the open version has even fewer restrictions but presently is not as complete as the standard version. This might change in the near future.

12.1.1 Building SSH2

  1. Full details on SSH2, including documentation, license information, and downloads, are available from the official Web site or a trusted mirror.

    www.ssh.com

    For simple downloads, a popular mirror in the U.S. is

    ftp://ibiblio.org/pub/packages/security/ssh/

    The following site may be used just for downloads:

    ftp://ftp.ssh.com

  2. Uncompress the downloaded file into a tarball and extract its files (where x is the minor version number):

     
     tar -xzpf ssh-2.0.x.tar.gz 

    Do a cd to the resulting directory.

     
     cd ssh-2.0.x 
  3. Read the README file.

  4. Compile ssh2.

    Version 2 can be built to offer compatibility with the previous version (ssh1). If you might want to do this, read the SSH2.QUICKSTART file. Note that there is a buffer overflow vulnerability with SSH versions 1.2.27 and earlier, so you do not want to talk to systems with these versions. Tell their SysAdmins to read "Upgrade SSH" on page 112. There also is a buffer overflow vulnerability in some versions of openssh. The following will do a basic SSH2 build:

     
     ./configure make 

    The following will enable it to use TCP Wrappers:

     
     ./configure --with-libwrap make 

    The following will disable support for X and is recommended for high-security systems such as firewalls and servers:

     
     ./configure --without-x --with-libwrap make 
  5. Install ssh2 by invoking the following command as root:

     
     make install 
  6. Some people remove the tarball and all sources to make it slightly harder for a rogue to introduce a Trojan horse. I think that this lack of availability of the source for building on other systems would be more of an inconvenience than the slight benefit.

    A compromise might be to move the source to a nonproduction system or to save it to tape. Elsewhere in the book, it is suggested to not keep compilers on production machines (for those wanting the highest security).

  7. If the /etc/services file does not have entries for port 22, the following line should be added. Although not necessary for proper operation, it would be less confusing when you map ports later. (Do not worry about crackers; they know all of this stuff.)

     
     ssh     22/tcp  # SSH Remote Login Protocol 
  8. In a standard configuration the SSH daemon, sshd, should be started automatically when the system starts up. On any distribution that supports the /etc/rc.d/rc.local file, add the following lines to it. This includes Red Hat, Mandrake, and Slackware. For distributions supporting the /etc/rc.d/rc3.d directory, a S* and K* file can be created.

     
     # Running sshd echo "Running sshd..." /usr/local/sbin/sshd & 

    As an alternative, sshd can be started via inetd. One advantage of this is that you get TCP Wrappers automatically. This is because by default sshd is not built to be libwrap-enabled. A disadvantage of this is that if inetd is compromised, sshd is subject to some vulnerabilities. Of course, in this case the cracker already has root access so he can take over sshd more directly. For this method, instead of starting sshd at system startup add the following line to /etc/inetd.conf. (Note that the directory that sshd is installed in can vary.)

     
     ssh stream tcp nowait root /usr/sbin/tcpd /usr/local/sbin/sshd -i 

    The -i tells sshd that it is invoked from inetd. You might need to edit the /etc/hosts.allow file to enable the ssh protocol (port 22) for the desired client hosts. In this example, all hosts in the pentacorp.com class-C network are enabled.

     
     sshd: 216.247.56.0/255.255.255.0 

12.1.2 Configuring SSH

These details will be specific to SSH2 version 2.0.13 but should be very close for other versions of SSH2 and similar to openssh and SSH1 too. Where the actual keys are stored was somewhat different in SSH1 and, no doubt, somewhat different for openssh but any good SysAdmin should be able to handle the differences. The system-wide configuration files for ssh and sshd are, respectively,

 
 /etc/ssh2/ssh2_config /etc/ssh2/sshd2_config 

The NoDelay option may be changed to yes to improve performance; it enables the socket TCP_NODELAY option. The options AllowHosts and DenyHosts each can be given a space-separated list of host names or IP addresses. The * and ? characters may be used in host names; they operate the same as with the shell. They match any number of characters or a single character, respectively.

The RequireReverseMapping option in sshd2_config will cause SSH to refuse connections from a client if a reverse DNS lookup on its IP address fails to resolve to a host name. This weak Ring of Security is useful to block crackers who change a compromised system's IP to some unused value and then start brute force guessing SSH passwords. Unfortunately, many ISPs are too lazy to provide reverse DNS lookup values to the dynamic IP addresses that they hand out to customers. If you have one of these, this Ring will keep you out too. In any case, for good security use strong passwords to prevent quick guessing and an Intrusion Detection System, such as my enhanced Logcheck program, to detect brute force password guessing.

The LoginGraceTime option specifies how many seconds the server will allow for a client to login. It defaults to 600, to allow 10 minutes. While 10 minutes should be enough to try the three to five times that most servers allow, I sometimes find myself distracted and timed out. A value of 1800 or 3600 may be reasonable. A value of 0 allows infinite time to log in or for a cracker to use up all of your connections easily.

The VerboseMode option is equivalent to -d 2 on the command line. It enables light debugging and causes sshd to not fork itself into the background. It also causes debugging information to go to standard error instead of to /var/log and will cause sshd to exit after the first connection terminates. I find this option useful when debugging the interaction between two systems, especially when the client is invoked noninteractively.

The KeepAlive option, which defaults to yes in sshd2_config and ssh2_config, causes both the client and server to send a periodic "keep alive" packet. If each side fails to see such a packet for a while, it assumes that the network or other system has gone down and drops the connection. This packet also will keep an IP Masqueraded connection open. Alternatively, if you want "forgotten" IP Masqueraded SSH connections to be dropped when your firewall's NAT inactivity timeout interval is reached, set KeepAlive to no in ssh2_config and sshd2_config. IP Tables' IP Masquerading inactivity timeout value is hardwired to 12 hours (not using even a defined constant) and IP Chains defaults to 12 hours.

In SSH2, the directory $HOME/.ssh2/hostkeys on the client is used to store server systems' public keys. Within this directory, public key file names have the form key_server-port_server-name.pub and, if missing, will be created automatically during startup on the first connection to that port of that server.

The client system also has host keys /etc/ssh2/hostkey.pub and /etc/ssh2/hostkey, where the key with the .pub extension is, naturally, the public key for this system and the other is the private key. These files were generated as one of the last steps of the make install and, of course, only need to be generated a single time for the host system.

Each user first needs to create his own authentication key with ssh-keygen. Normally, each user invokes ssh-keygen without any arguments and it will generate his authentication key and then ask him for his passphrase. This passphrase is a password that is used to encrypt the authentication key before storing it in a file on disk so that not even root can use it and pretend to be you (though root can insert a Trojan version of ssh, sniff your keyboard or display, etc.).

A typical dialogue with ssh-keygen for a user creating his authentication key and pass phrase follows. The user's input is in bold. The actual password (secret in this example) is not echoed. Please see "Avoiding Weak and Default Passwords" on page 42 for details on how to create good hard-to-break passwords. Each user needs to do this setup once.

 
 % ssh-keygen RETURN Generating 1024-bit DSA key pair    3 o.oOo..oOo.o Key generated. 1024-bit dsa, dbcooper@laptop, Sun Feb 27 2000 13:09:03 Passphrase : secret RETURN Again      : secret RETURN Private key saved to /home/dbcooper/.ssh2/id_dsa_1024_a Public key saved to /home/dbcooper/.ssh2/id_dsa_1024_a.pub % 

Both keys must reside on the client; only the public key should reside on the server.

Note that the private and public keys end in _a and _a.pub, respectively. Subsequent invocations of ssh-keygen will generate files with "b", "c", and so forth. By default, the server's configuration file specifies that validation may be done by key pair (authentication key) or by password. The sshd2_config file may be edited to require that both of these be provided or to accept only the public key or only the password. Requiring the public key allows control of which client system may log in, with this control immune to DNS, routing, MAC, or similar spoofing or hijacking.

While SSH will allow unlimited guesses of the password (if this authentication is allowed), by first requiring the authentication key this problem is eliminated. Since guessing a 1024-bit key is essentially impossible, only those that possess the key will be logging in. This key is called public because it is known to other than just the system that created it. However, unlike PGP public keys, it should be given only to those whom access is granted to. To detect excessive password guessing, the log files should be monitored, as discussed in "Paging the SysAdmin: Cracking in Progress!" on page 620.

If P is given to ssh-keygen, the no pass phrase will be required. This is especially useful for scripts, assuming that the client's system and account are secure. Select and change your pass phrases as you would your passwords. "Passwords A Key Point for Good Security" on page 41.

Requiring only the public key to log in and having an empty pass phrase on the client will allow unattended scripts on the client system to log in and do work, such as automatic secure backups, without a human to enter passwords. Even with absence of passwords, this arrangement is secure so long as the respective accounts and root accounts on the client and server systems are properly configured and otherwise secure. By generating multiple pairs of public and private keys, different "public" keys may be given to different server systems. To disable access by one client, perhaps that of a vendor or consultant, simply remove its public key from the server.

The SSH documentation is vague on how to arrange public key authentication. The client system user decides which key pair to use; id_dsa_1024_a and id_dsa_1024_a.pub that were generated on the client system with ssh-keygen, for example. Both must be on the client system. On the client system, create the file $HOME/.ssh2/identification with the following line to specify a private key to use:

 
 IdKey   id_dsa_1024_a 

Copy the respective public key, id_dsa_1024_a.pub, to the server system and ensure that it is identical. The scp program or even ordinary e-mail may be used. If an untrustworthy method is used for this copying, invoke md5sum to ensure identical copies. Store this file on the server system in the $HOME/.ssh2 directory, perhaps as joe.homesys.id_dsa_1024_a.pub. Then, on the server system, create the file $HOME/.ssh2/authorization containing the line

 
 Key     joe.homesys.id_dsa_1024_a.pub 

Both the identification and authorization files may list multiple keys. During login negotiations, all combinations will be tried until a match is found. The server verifies that the client has the respective private key of a public key it is trying by using the public key to encrypt a random number that only it knows. The client must decrypt the message containing this number with its private key and return the correct number to the server. This session already is encrypted so no one else can hijack it.

12.1.3 Using SSH

graphics/fivedangerlevel.gif

To connect to research.pentacorp.com and have your standard shell start up for interactive use and on the same account name as you are using on the client system, simply issue the following command:

 
 ssh research.pentacorp.com 

To connect to the joe account, specify that with -l.

 
 ssh -l joe research.pentacorp.com 

In these cases, because no command has been specified on the server, ssh uses a pseudo tty automatically so that the remote shell thinks that it is talking to a tty device. The name of the remote system may be followed by a remote command to be executed instead of the remote user's default shell. In this case, by default, no pseudo tty is created and the remote program probably will buffer up its output. This makes the use of interactive applications difficult but is practical for noninteractive applications.

For the example, you want to run a tar command on the client but have the archive be written to a tape drive on the server system. Although many SysAdmins fail to carefully guard backup files or worry about network backup sessions being sniffed, you are more careful. You will do a full backup to /dev/rmt0 on server.pentacorp.com. The following command will work:

 
 cd / tar -cf - . | ssh server.pentacorp.com \    dd ibs=10k obs=10k of=/dev/rmt0 

The ssh program will prompt you for the password on standard error and will read the password from /dev/tty instead of standard input. (If you are using authentication key validation, a password will not be needed.) Note that the dd command uses obs=10k to properly block the output; bs=10k will not work because if an inputted block is smaller, that size will be written. The obs=10k will reblock as needed to obtain 10 KB blocks.

If the remote program expects to be talking to a tty device, the -t flag should be given to cause a pseudo tty to be allocated. By default, this is done only if a remote command is not specified. The -n flag will redirect standard input from /dev/null. The -f flag will cause ssh to fork itself into background after authentication is complete. The +C flag enables compression of data before transmitting it over the connection. The +t flag enables a pseudo tty even if a remote command was given while -x disables X forwarding.

12.1.4 Wrapping SSH Around X

graphics/fivedangerlevel.gif

The easiest way to wrap SSH around X so that your users' X sessions are protected is to have them use ssh to connect into the server system and allow X to set their $DISPLAY environment variable. This will cause this X to go through SSH. The resulting encrypted communication is protected from sniffing and spoofing. Specifically, SSH will set the X session to be greater than 0 and have sshd provide service for that session and route it over the SSH encrypted port initiated via TCP port 22. This encrypted route will not use the 6000 series ports.

Note that session 0:0 uses port 6000, session 1:0 uses port 6001, etc. SSH starts out with session 10:0 and listens on local port 6010 to capture the X sessions and diverts them to travel over its encrypted and protected channel initiated via TCP port 22.

Note that the user accidentally set his $DISPLAY variable on the server system, if anything is either empty or the name of the server system there still is no data going over the Ethernet "wire" so the only sniffing that is possible is from your account on the server or from root. However, others might be able to attach to the X server and compromise you. If anything is a third system, i.e., not the client or server, the connection is subject to sniffing by anyone on the LAN. This latter problem can be protected against by using IP Chains to block access to the 6000 series of network ports from other systems. This is discussed in "X Marks the Hole" on page 117.

Thus, it is strongly recommended that IP Chains be used to block the 6000 series ports from getting off the local machine. Thus, if a user accidentally sets his $DISPLAY, his insecure attempt will be blocked. The IP Chains commands to do this and more valuable information are in "X Marks the Hole" on page 117, which is must reading!

X forwarding can be disabled with the use of the ssh command-line -x flag.

ssh X security trap #1

A common error is for a user to set the $DISPLAY environment variable in his shell startup script on the server system, thus overriding ssh's setting of it. After correctly logging in with ssh, the

 
 echo $DISPLAY 

command should show

 
 server.pentacorp.com:10.0 

not


anything:0.0     Wrong!

The user needs to set the $DISPLAY variable on the client system and not set it on the server to cause this X forwarding to happen automatically.


ssh X security trap #2

Another error is for a user to set the $DISPLAY environment variable on the client system to be a third system. This will cause ssh to establish a secure encrypted path from the server system to the client system but then establish an insecure connection from the client system to the third system. The ports or netstat programs may be used to show either these insecure connections or the absence of them.

If ssh was used properly from the third system to connect into the "client" system and from there a second ssh was used to connect to the "server" system, security will be maintained. The problem typically will occur if the $DISPLAY variable on the "client" system was set manually to point at the X server on the third system. This might be via an incorrect shell startup script. Again, IP Tables or IP Chains may be used to block this problem.


12.1.5 Using sftp

graphics/fourdangerlevel.gif

The sftp program implements a secure equivalent to FTP; the name means secure FTP. It takes an argument, which is the name of the server. A second argument, if present, specifies the name of the remote account. It is available with SSH2 and, since mid-2000, with OpenSSH.

12.1.6 Using scp

graphics/fourdangerlevel.gif

The scp program implements a secure equivalent to rcp; the name means secure cp. It is part of the SSH suite of programs. It takes two arguments; they are the names of the source and destinations, respectively. Each may be an ordinary filename or host:file or user@host:file. The shell's "*" and "?" wildcards are processed. To copy .profile to research.pentacorp.com, issue the following command:

 
 scp .profile research.pentacorp.com:.profile 

12.1.7 Wrapping SSH Around Other TCP-Based Services

graphics/fivedangerlevel.gif

A good source of additional information on SSH-wrapping TCP ports is in

http://csociety.ecn.purdue.edu/~sigos/projects/ssh/forwarding/

SSH allows mapping any local TCP port to any port on a remote server. The local system connects to port 22 of the remote system and sshd on the remote system then connects to the specified remote port. Thus, a firewall can block all but TCP port 22 and because the port 22 traffic is encrypted and secure, this connection is safe from sniffing and "Man-in-the-middle" attacks. This allows secure access to remote servers.

For example, Pentacorp has an application that lets employees file Expense Reports online. It is a server that runs on TCP port 978 on hr.pentacorp.com. Obviously, the firewall blocks access to port 978 from the Internet for security. It has a client-side program called expense, which has a single argument. This argument is the name of the server system and it knows to connect on port 978. When an employee is in the office, from her desktop behind the firewall, she can issue the command

 
 expense hr.pentacorp.com 

When she is on a business trip, she can issue the following commands to establish a secure connection, sometimes called a Virtual Private Network or VPN. Then she invokes the expense command. Both of these would be invoked on her laptop that is connected to her ISP via PPP.

 
 ssh -S -f -L 978:hr.pentacorp.com:978 hr.pentacorp.com expense user_1234.isp.com 

Many proprietary closed-source operating systems rely on "Security by Obscurity." This is the concept that only the vendor's programmers will see the code and, therefore, only they will know about its security holes. System administrators will learn about other holes but never would tell anyone. In the old days, when most systems were not on the Internet, only a few people with enough talent to make use of one of these holes had access to a system. With the Internet much smaller then and most access only by company accounts, it was easy to determine who posted information about these holes. This discouraged dissemination as well.

Now the Internet allows one person to share knowledge of these holes with thousands through means intended for crackers. System administrators will hear about these holes later, after damage has been done. This sharing can be done easily from an anonymous remailer, a stolen account, or an account at a public library. Some of the thousands reading about them then will use these holes against thousands of Internet-connected systems. A hundred crackers poring over a piece of code and experimenting with it are more likely to find holes in it than the two to six people that typically maintain any particular piece of proprietary code.

Alternatively, if a proposed encryption system is disseminated publicly, a thousand "white hats" might review it for weaknesses. This can be done prior to use, allowing weaknesses to be addressed before the system is being trusted. This is in stark contrast to the consequences of an encryption algorithm that already is in use being cracked. The cracked algorithm compromises the millions of documents that hundreds of thousands of people might be trusting that algorithm to protect. If one user's key or password is breached, only that person's documents are compromised.

The failure of Security by Obscurity is that the small increase in security due to holes staying secret temporarily is offset by the much greater chance of undiscovered security holes. This is because large numbers of "white hats" are not allowed to discover the problems before "black hats" do. A common practice in the open-source world when a vulnerability is found is to notify the maintainer of the software first and allow them a week to create and distribute a fix and then to publish the problem in popular security lists such as Bugtraq and X-Force's Alert. The major distributors of Linux and BSD, Sendmail, Inc., and others seem comfortable with this arrangement. Many security experts consider Security by Obscurity to be an oxymoron.


The -S flag tells ssh not to create a session channel. That is, do not create the normal pseudo tty channel with an interactive shell. The -f flag tells ssh to fork itself into the background after authentication. This also causes ssh to exit after the connection is broken by either side. The

 
 -L 978:hr.pentacorp.com:978 

tells ssh to establish a VPN connection from local port 978 to hr.pentacorp.com and connect to port 978 on hr.pentacorp.com. Note that

 
 -L 1234:hr.pentacorp.com:4321 

would have caused ssh to listen on local port 1234 and bridge it to port 4321 on hr.pentacorp.com. Lastly, the remote host name is specified.

12.1.8 Vulnerabilities SSH Cannot Protect Against

graphics/fivedangerlevel.gif

Note that anyone, root or otherwise, who can access your keyboard or screen data or memory (RAM) while you are using SSH (or who can intercept this data while it is en route to or from your applications) can sneak around SSH security by seeing your passphrase, by seeing the data you plan to send before it is encrypted, or after received data is decrypted, and possibly alter it. Note that if you have not properly configured X, anyone on the Internet can read your keystrokes going to any program that passes through X. See "X Marks the Hole" on page 117 to configure X properly. "SSH Dangers" on page 511 and page 542 is must reading for a discussion on the dangers of allowing SSH connections into the organization from users' home systems. If you have this problem (of others being able to see data before SSH can encrypt it or after SSH has decrypted it), your system is possibly already compromised. If this is the case, clearly you need to go to Part IV of this book, "Recovering from an Intrusion," immediately.

Other than the system being compromised completely, the only likely ways that a user account could be compromised would be:

  1. The user's password was broken through exhaustive searching because it was weak or because they used a lot of computrons (CPU time).

  2. They sniff the network while the user supplied her password in clear text to a program like telnet, ftp, or a pop server.

  3. The user was tricked by a login simulator or screensaver simulator. (See "Defeating Login Simulators" on page 325.)

  4. Through the use of an insecure or buggy program, they were able to execute their code and, say, alter the user's search path to invoke their SSH containing a Trojan.

If any of these are suspected, see Part IV, "Recovering from an Intrusion," immediately!


   
Top


Real World Linux Security Prentice Hall Ptr Open Source Technology Series
Real World Linux Security Prentice Hall Ptr Open Source Technology Series
ISBN: N/A
EAN: N/A
Year: 2002
Pages: 260

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net