Channels ▼


Automate SSH Logins by Customizing Putty

Driving PuTTY

This login program is now complete save for one detail: I need a way to send my responses back to AutoPutty.

The first part of this is pretty obvious — I just need to read the data from the dialog box and post it to AutoPutty with my useful WM_COPYDATA command. This happens in my WM_APP+1 handler:

afx_msg LRESULT CPuttyDriverDlg::OnWmAppPlusOne(WPARAM wParam, LPARAM lParam)
    CString msg;
    switch ( wParam ) {
    case 0 :
        msg = this->m_UserId + '\r'; break;
    case 1:
        msg = this->m_Password + '\r'; break;
    if ( this->m_PuttyWindow ) {
        cd.dwData = (ULONG_PTR) 0xF00DFACE;
        cd.cbData = msg.GetLength();
        cd.lpData = (PVOID) (const char *) msg;
        ::SendMessage( this->m_PuttyWindow, 
                       (WPARAM) this->m_hWnd, 
                       (LPARAM) &cd );
    return 0;

Sending this data to AutoPutty is fine, but right now the program doesn't do anything with that message. The final piece of work is to add a WM_COPYDATA handler to window.c.

Simply grabbing the data is easy enough — the data structure that accompanies the message contains a pointer to the data and a value indicating its length. However, I have two problems I have to solve before the data is actually sent out to the to whatever device AutoPutty is connected to.

First, I have to take into account the fact that PuTTY was written to use wide characters. My driver program was built using MultiByte characters, so we have a mismatch. This means I have to do a conversion of the data from one domain to the other. This is a two step process - I call MultiByteToWideChar() once to determine how much space I need, then I allocate a buffer and call it again.

The second thing I need to do is determine what to do with the data once I've converted it. PuTTY takes all terminal input and eventually passes through a function called luni_send(). Calling this function directly from the Windows procedure seems to work just fine.

The WM_COPYDATA handler I created looks like this:

    int wsize = MultiByteToWideChar( CP_ACP,
                                     (LPCSTR) cd->lpData,
                                     0 );
    wchar_t *buf = (wchar_t *) calloc( wsize+1, sizeof(wchar_t) );
    MultiByteToWideChar( CP_ACP,
                         (LPCSTR) cd->lpData,
                         wsize + 1 );
    if (term->ldisc)
        luni_send(term->ldisc, buf, wsize, 0);
    free( buf );

At this point, I have a working program - it connects to my designated host, and sends the username and password of my choice to the host, connecting me to the system.

I should add a note of caution here: Automating logins is a tempting time saver, but in general, this is a really bad idea. Any time you hard code credentials into a program, you open the door to all sorts of new attacks on your system.

In my video demo program, the user has to enter a name and password, so nothing is hardcoded, but even this adds security holes to a system. I encourage you to think of this as a demonstration only.

Source Code

I've included the complete source code for PuttyDriver, the MFC project that controls AutoPutty. It was built with Visual Studio 2010, so you may have a little work to do if you backport it to earlier versions. My use of language features and classes should be compatible with much earlier versions — this is all very simple code.

Because PuTTY is always changing, I am not redistributing a snapshot of the version I used. Instead, I'm including before and after copies of the two source files I modified: window.c and terminal.c. If you build with Putty 0.61, you should be able to drop these two files right on top of the files included with the distribution and be on your way. With later versions of PuTTY you will have to perform an intelligent merge of the changes, which I hope will be a fairly effortless process.


  • The PuttyDriver source and project. You will need to add the PuTTY project to this solution as described in the article.
  • This contains the two PuTTY source files modified for this project. Both the original 0.61 source and my modified source are supplied. Executables are supplied as well, which may or may not work on your system.

Related Reading

More Insights

Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.