Primer on SSH and SCP
Hardly anyone uses telnet to log into their UNIX shell anymore. And with good reason; the idea of having your password transmitted in clear text (i.e. unencrypted), thus easily obtained by nosey people equipped with the proper sniffing tools, just isn't all that appealing. The replacement for telnet is SSH, which stands for SecureSHell and became mainstream quite a number of years ago. Popular clients are the commercial SecureCRT, the free Teraterm, and the also free and extremely popular PuTTY.
But while most of us take the usage of SSH for granted, there are still a surprisingly larger number of people that use FTP to copy their files onto their (SSH enabled) web server — even though FTP is just as insecure, transmitting username and password in clear text. Not only that, but having to keep typing in a password (for SSH and FTP) is annoying as well. The solution to this first and foremost insecure problem is very simple:
Key-based authentication
The idea behing key based authentication is rather simple, while the mathematics behind it are a lot more complicated. Let me try to explain it in non-cryptographer terms.
Technically we create a key-pair. The pair consists of a private key, which we keep secret, and a public key, which we send out to others — or the server we want to access in this case. The private and public key are mathematically related, yet it is computationally infeasible to deduce one from the other. Anyone with the public key can encrypt a message but not decrypt it. Only the person with the private key can decrypt the message. Thus, things are fairly secure.
The necessesary tools
For starters, we'll need two tools: PuTTY, a small and free, but powerful SSH client. And WinSCP, an explorer-like SCP client, which supports drag’n’drop, a file upload queue, integrated file viewer, editor, and much more. WinSCP also ships with PuTTYgen and Pageant, of which we'll need both. We could also download PuTTYgen and Pageant from the PuTTY download page directly, but since we'll use WinSCP, too, it would be an unnecessary step.
Download and install both (PuTTY has to be installed manually by copying putty.exe to the harddrive and creating a shortcut on the desktop, or placing putty.exe on the desktop directly.)
SSH key generation
Now let's create the key that will be used to access the server. PuTTYgen is used for this task. It can be found in “Start / Programs / WinSCP3 / Key tools / PuTTYgen”.
Once started, at the bottom of PuTTYgen, change the parameters to SSH2 RSA. You can leave the number of bits set to the default of 1024, or if you're really paranoid, increase the number. 4096 is considered overkill. Click “Generate”. After the key has been generated, change the key comment to “yourname’s Access key”. The comment doesn't really have any functionality other than being helpful if you're using multiple keys. Setting a pass phrase is highly recommended. If you don't, anyone who gains access to your private key will be able to use it. Save the private key to your hard drive. Name it “yourname-access-key.ppk” and, if possible, keep a secure backup copy of it on a floppy, USB memory stick/watch, etc. Keep the PuTTY Key Generator open for the next step.
Configuring PuTTY
I'll use phpwebhosting.com as an example since they're fairly popular. Most other hosting services will work similarly.
Start PuTTY. Enter the hostname of your web server (i.e. zeus.phpwebhosting.com). Select the SSH protocol. In the "Connection" settings, set Auto-login username to your username (i.e. your FTP username). Enter a value of 60 for Seconds between keepalives (Seems to help with certain routers and hosting providers). In the "Connection / SSH / Auth" settings, browse to your private key (your .ppk file we just created during the last step). Then go back to the "Session" settings, type in a session name (e.g. phpwebhosting) and click Save. Double click on the saved session or click on Open to connect to the server.
You should get a prompt similar to this one:
Using username "marcus" marcus@zeus.phpwebhosting.com's password:
But wait, that's nothing new. How come the server didn't automagically log me in? That's because the server doesn't have a clue what to do with the private key — it doesn't have our public key yet. So, for now type in the account's password to get to the shell.
Telling the server about our new key
The SSH server so far has no way of verifying our private key. We'll first need to give it the public key, which needs to be stored in ~/.ssh/authorized_keys2. Go ahead and use your favorite editor (vi, emacs, pico, nano) to do that. Or, if you want to, try the following method:
First, let's go into the .ssh directory.
No mail. Last login: Sat Nov 13 12:19:55 2004 from c-24-131-102-112 marcus@zeus:~$ cd .ssh marcus@zeus:~/.ssh$
Copy the key from the PuTTY Key Generator, and in PuTTY type:
marcus@zeus:~/.ssh$ cat >> authorized_keys2
Now paste your key using SHIFT+INSERT, hit ENTER for a newline, and press CTRL+D, to signal the end of input. That's it.
The server should now be aware of your public key. And just to be sure, do the following:
marcus@zeus:~/.ssh$ chmod 644 authorized_keys2
That will set the permissions so only you have access to the file. Fair Warning: If you skip this step, the SSH server may not want to read your authorized_keys2 file.
Now open a new PuTTY window, and log in again. This time, it should look somewhat like this:
Using username "marcus". Authenticating with public key "Marcus' Access Key" Passphrase for key "Marcus' Access Key":
And you'll be prompted to enter your key's pass phrase. If you opted to not use a pass phrase, you should be logged in by now.
Pageant – the PuTTY key agent
To avoid needing to constantly type in your pass phrase for PuTTY (and WinSCP), it is recommended that you setup and use Pageant, the PuTTY key agent. It also can be found in “Start / Programs / WinSCP3 / Key tools / Pageant”. Start it. It will appear in your system tray as a little computer wearing a hat.
Double click on the Pageant tray icon to open the Pageant Key List window. Click "Add Key", and browse to your private key. You will be prompted to provide your password. After entering your password, your key will appear as an entry in the key list. You can now close the Key List window.
Start another PuTTY session to your web host. You should not need to provide your pass phrase anymore. The login process should look somewhat like this:
Using username "marcus". Authenticating with public key "Marcus' Access Key" from agent No mail. Last login: Sat Nov 13 12:56:05 2004 from c-24-131-103-111 marcus@zeus:~$
From now on, just load Pageant, load your private key, provide your pass phrase once, and you'll have easy access to your shell account. This works especially well if you manage multiple accounts using the same key. Of course security advocates will tell you to generate a new key for each account.
Setting up WinSCP is rather self explanatory. And with Pageant running, logging in is just as simple.
Other programs, such as TortoiseSVN benefit from a key-based authentication setup as well, if you're using the svn+ssh:// protocol.
Print This Post
Firefox 1.0 released
Time to upgrade, folks. I'm currently still using Firefox 0.9.3, and it's proven itself to be an excellent replacement for Microsoft Internet Explorer.
Print This Post
Auto-properties in Subversion
I'm a big fan of Subversion and use it for nearly every project I work on. I work on our software projects in several ways: On the Linux development server directly, which I access from a Windows desktop using UltraEdit (Load/Save via SFTP), WinSCP, PuTTY, and the command line svn client. On my Windows PC, with Apache 2, PHP5, MySQL 4 and PostgreSQL 8 installed, using TortoiseSVN. On my Windows Laptop, also with Apache 2, PHP5 and MySQL 4, and TortoiseSVN installed, so I can develop and test anywhere I am.
Not too long ago I noticed that the auto-properties in Subversion weren't applied when adding new files in TortoiseSVN on my windows machines.
On the development server where I work some of the time the /etc/subversion/config file looks like this:
[miscellany] enable-auto-props = yes [auto-props] *.php = svn:keywords=Id *.phtml = svn:keywords=Id *.lx = svn:keywords=Id *.mysql4 = svn:keywords=Id *.sql = svn:keywords=Id *.tlx = svn:keywords=Id *.txt = svn:keywords=Id *.css = svn:keywords=Id *.js = svn:keywords=Id
That config file is used by the commandline svn client and makes sure that all file with the listed extensions have their svn:keywords property set to Id.
On Windows, however, the equivalent (actually, the per-user configuration) file is located at C:/Documents and Settings/<username>/Application Data/Subversion/config. This file has the same format as the UNIX equivalent.
If you're not familiar with keyword substitution or the svn:keyword feature at all, you may want to read up on it. I typically stick the following header into every file:
/*
User Signup page
User Management module
Copyright 2004 Lucidix, Inc. All rights reserved.
$Id: signup.lx 2341 2004-11-01 18:04:01Z marcus $
*/
Print This Post
PHP5 headaches
At Lucidix we decided to test run our workflow software on PHP5 and, if all goes well, to forget about backward capability with PHP4. There's one really good reason for it; Exception handling.
We've tested the web app on Win XP, Apache 2.0.50, MySQL 4.0.20 and PHP5.0.0. Everything ran great. I started implementing exceptions and all was well. So we upgraded our linux based development server to PHP5.
First problem was getting PHP5 to compile — with MySQL support that is. After removing the older libmysqlclient10-dev package and installing gcc-3.3 it finally compiled and installed fine.
We restarted the web server, opened the browser window and already the login feature is broken. After checking the links, and trying to figure out why it would come up as "The page cannot be displayed" for about an hour, we checked the server log.
[Sat Jul 22 20:54:26 2004] [notice] child pid 9677 exit signal Segmentation fault (11)
Great. Just beautiful. Since I was the one who pushed for PHP5, everybody was looking at me to fix it. Can't argue with that.
First thing I did was grabbing an older revision from the subversion repository, before PHP5 features were implemented. I tried to login and got the same error. Ok, so it's not the new features.
Perhaps our dev server is just screwed up. Everything else seems to run stable, but you never know. Could be conflicting libraries. After all, it barely compiled. Mixing debian/stable and debian/testing may not have been the wisest decision. So let's see if the problem is unique to this box (hey, it ran on WinXP).
So I used another box, installed debian 3 and grabbed the PHP5 backport from http://www.dotdeb.org/. I didn't want to have to go through the whole setup of MySQL, so I just tunneled port 3306 through SSH to another MySQL server.
I fired up the browser, entered the IP, and got the login prompt. Entered username, and password, and wham, got the same Segmentation fault. Conclusion: It must be PHP5. Now what?
Submit a bug, perhaps. First I should first find out what's going on and more importantly, where it's breaking.
I went on to recompile PHP5 with the --with-debug flag, shut down Apache , and ran it in gdb.
gdb /usr/sbin/apache
(gdb) run -X
Pointed the browser at the page, and stared at the screen.
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 16384 (LWP 14544)]
0×40754cf2 in _zval_ptr_dtor (zval_ptr=0×5a5a5a5a,
__zend_filename=0×407dd140 "/usr/local/src/php-5.0.0/Zend/zend_variables.c", __zend_lineno=193)
at /usr/local/src/php-5.0.0/Zend/zend_execute_API.c:389
389 (*zval_ptr)->refcount–;
(gdb)
Beautiful. Apparently something in there reference counting mechanism doesn't work quite right. I Backtraced it..
#0 0×40754cf2 in _zval_ptr_dtor (zval_ptr=0×5a5a5a5a,
__zend_filename=0×407dd140 "/usr/local/src/php-5.0.0/Zend/zend_variables.c", __zend_lineno=193)
at /usr/local/src/php-5.0.0/Zend/zend_execute_API.c:389
#1 0×4076140d in _zval_ptr_dtor_wrapper (zval_ptr=0×5a5a5a5a)
at /usr/local/src/php-5.0.0/Zend/zend_variables.c:193
#2 0×4076bd83 in zend_hash_clean (ht=0×82c2adc) at /usr/local/src/php-5.0.0/Zend/zend_hash.c:545
#3 0×4078ef63 in zend_do_fcall_common_helper (execute_data=0xbfffec50, opline=0×82cb64c,
op_array=0×82c8bbc) at /usr/local/src/php-5.0.0/Zend/zend_execute.c:2749
#4 0×4078f2ef in zend_do_fcall_by_name_handler (execute_data=0xbfffec50, opline=0×82cb64c,
op_array=0×82c8bbc) at /usr/local/src/php-5.0.0/Zend/zend_execute.c:2810
#5 0×4078acc4 in execute (op_array=0×82c8bbc) at /usr/local/src/php-5.0.0/Zend/zend_execute.c:1391
#6 0×4078edd5 in zend_do_fcall_common_helper (execute_data=0xbfffed40, opline=0×82f42dc,
op_array=0×82ec8cc) at /usr/local/src/php-5.0.0/Zend/zend_execute.c:2728
#7 0×4078f2ef in zend_do_fcall_by_name_handler (execute_data=0xbfffed40, opline=0×82f42dc,
op_array=0×82ec8cc) at /usr/local/src/php-5.0.0/Zend/zend_execute.c:2810
#8 0×4078acc4 in execute (op_array=0×82ec8cc) at /usr/local/src/php-5.0.0/Zend/zend_execute.c:1391
#9 0×40756674 in zend_call_function (fci=0xbfffeeb0, fci_cache=0×0)
at /usr/local/src/php-5.0.0/Zend/zend_execute_API.c:835
#10 0×407555ac in call_user_function_ex (function_table=0×8150288, object_pp=0×0,
function_name=0×829541c, retval_ptr_ptr=0xbfffef14, param_count=2, params=0×82bd244,
no_separation=1, symbol_table=0×0) at /usr/local/src/php-5.0.0/Zend/zend_execute_API.c:550
#11 0×40755463 in call_user_function (function_table=0×8150288, object_pp=0×0,
function_name=0×829541c, retval_ptr=0×8357e9c, param_count=2, params=0xbfffef98)
at /usr/local/src/php-5.0.0/Zend/zend_execute_API.c:525
#12 0×4061a59b in ps_call_handler (func=0×829541c, argc=2, argv=0xbfffef98)
at /usr/local/src/php-5.0.0/ext/session/mod_user.c:60
#13 0×4061abcb in ps_write_user (mod_data=0×4082feb0,
key=0×829590c "33d204aaa6fe101d1dc25d3815b91162",
val=0×835a4d4 "theme|s:7:"default";navmenu|s:4770:"var myMenu = [[' ', 'My Office', '/index.lx?_mod=transact&_file=index', '_self', 'Go to My Work"…, vallen=5259) at /usr/local/src/php-5.0.0/ext/session/mod_user.c:148
#14 0×40614d51 in php_session_save_current_state ()
at /usr/local/src/php-5.0.0/ext/session/session.c:802
#15 0×40619049 in php_session_flush () at /usr/local/src/php-5.0.0/ext/session/session.c:1708
#16 0×40619074 in zm_deactivate_session (type=1, module_number=7)
at /usr/local/src/php-5.0.0/ext/session/session.c:1722
#17 0×40767fa0 in module_registry_cleanup (module=0×80e3b88)
at /usr/local/src/php-5.0.0/Zend/zend_API.c:1469
#18 0×4076c22e in zend_hash_apply (ht=0×40834380, apply_func=0×40767f5d )
at /usr/local/src/php-5.0.0/Zend/zend_hash.c:664
#19 0×40762ae5 in zend_deactivate_modules () at /usr/local/src/php-5.0.0/Zend/zend.c:804
#20 0×40715391 in php_request_shutdown (dummy=0×0) at /usr/local/src/php-5.0.0/main/main.c:1198
#21 0×40797c92 in apache_php_module_main (r=0×815c834, display_source_mode=0)
at /usr/local/src/php-5.0.0/sapi/apache/sapi_apache.c:60
#22 0×40798c85 in send_php (r=0×815c834, display_source_mode=0,
filename=0×815e364 "/home/marcus/public_html/webapp/trunk/index.lx")
at /usr/local/src/php-5.0.0/sapi/apache/mod_php5.c:622
#23 0×40798d0a in send_parsed_php (r=0×815c834)
at /usr/local/src/php-5.0.0/sapi/apache/mod_php5.c:637
#24 0×08053ab4 in ap_invoke_handler ()
#25 0×0806342c in ap_some_auth_required ()
#26 0×08063488 in ap_process_request ()
#27 0×0805cc6b in ap_child_terminate ()
#28 0×0805cdfc in ap_child_terminate ()
#29 0×0805cf19 in ap_child_terminate ()
#30 0×0805d3f5 in ap_child_terminate ()
#31 0×0805dafd in main ()
#32 0×400f4da6 in __libc_start_main () from /lib/libc.so.6
(gdb)
Most of the action happens in execute(), which is at frame 5. So let's look at that.
e (op_array=0×82c8bbc) at /usr/local/src/php-5.0.0/Zend/zend_execute.c:1391
1391 if (EX(opline)->handler(&execute_data, EX(opline), op_array TSRMLS_CC)) {
And the issue is where exactly?
(gdb) print (char *)(executor_globals.function_state_ptr->function)->common.function_name
Cannot access memory at address 0xc5(gdb) print (char *)executor_globals.active_op_array->function_name
$1 = 0×82c8abc "call"(gdb) print (char *)executor_globals.active_op_array->filename
$2 = 0×823d76c "public_html/webapp/trunk/gbl/src/class.backend2.lx"
Just wonderful. The backend. That's one of the more complicated pieces in the software. Oddly enough, there are several different seg faults PHP5 is spitting out. One was the same that is triggered during the WordPress login. Someone actually beat me to it and reported the bug. Although wordpress's bug tracker is not really the correct place for it, I added my comments to the report.
I recompiled PHP5 from CVS (php5-200407242230.tar.bz2) and the bug was fixed. WordPress works again, but our webapp still doesn't.
Great. I guess I'll have to work around it for now. At least two bugs are still in PHP5. One involves zend_hash_find
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 16384 (LWP 14081)]
0×4076c9e0 in zend_hash_find (ht=0×82327d4, arKey=0×8238db4 "filename", nKeyLength=9,
pData=0xbfffeaf4) at /usr/local/src/php-5.0.0/Zend/zend_hash.c:854
854 if ((p->h == h) && (p->nKeyLength == nKeyLength)) {
And the other one is a stream error.
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 16384 (LWP 14244)]
0×401568f7 in memcpy () from /lib/libc.so.6(gdb) bt
#0 0×401568f7 in memcpy () from /lib/libc.so.6
#1 0×40747b89 in _mem_block_check (ptr=0×83147b4, silent=0,
__zend_filename=0×407c6ca0 "/usr/local/src/php-5.0.0/main/streams/streams.c",
__zend_lineno=1551, __zend_orig_filename=0×0, __zend_orig_lineno=0)
at /usr/local/src/php-5.0.0/Zend/zend_alloc.c:722
#2 0×40747b4b in _mem_block_check (ptr=0×83147b4, silent=1,
__zend_filename=0×407c6ca0 "/usr/local/src/php-5.0.0/main/streams/streams.c",
__zend_lineno=1551, __zend_orig_filename=0×0, __zend_orig_lineno=0)
at /usr/local/src/php-5.0.0/Zend/zend_alloc.c:714
#3 0×40746cf7 in _efree (ptr=0×83147b4,
__zend_filename=0×407c6ca0 "/usr/local/src/php-5.0.0/main/streams/streams.c",
__zend_lineno=1551, __zend_orig_filename=0×0, __zend_orig_lineno=0)
at /usr/local/src/php-5.0.0/Zend/zend_alloc.c:265
#4 0×4072b7af in _php_stream_stat_path (
path=0×82008dc "/trunk/gbl/src/drv/proc_core_session_write.mysql4", flags=2, ssb=0xbfffe9c0, context=0×0)
at /usr/local/src/php-5.0.0/main/streams/streams.c:1551
#5 0×406ab629 in php_stat (
filename=0×82008dc "/trunk/gbl/src/drv/proc_core_session_write.mysql4", filename_length=91, type=15, returnvalue=0×82f5284)
at /usr/local/src/php-5.0.0/ext/standard/filestat.c:570
The night is still young, but it looks like it's going to be a long one.
Print This Post
Modified DBDesigner
Earlier today I modified DBDesigner to, above all, not delete columns automatically after renaming the destination column in a relationship. It also displays "AI" for auto_increment columns, so I don't have to guess anymore whether I forgot to check that AI column without opening up the edit box for every single table, as there are a fair amount of tables in the diagram.
Print This Post