diff --git a/cmdline.c b/cmdline.c index 29456a1f..82cd4f86 100644 --- a/cmdline.c +++ b/cmdline.c @@ -314,6 +314,13 @@ int cmdline_process_param(char *p, char *value, int need_save, Config *cfg) cfg->nopty = 1; } + if (!strcmp(p, "-N")) { + RETURN(1); + UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK); + SAVEABLE(0); + cfg->ssh_no_shell = 1; + } + if (!strcmp(p, "-C")) { RETURN(1); UNAVAILABLE_IN(TOOLTYPE_NONNETWORK); diff --git a/config.c b/config.c index cbf31698..8588b23c 100644 --- a/config.c +++ b/config.c @@ -1491,6 +1491,10 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist, HELPCTX(ssh_nopty), dlg_stdcheckbox_handler, I(offsetof(Config,nopty))); + ctrl_checkbox(s, "Don't start a shell or command at all", 'n', + HELPCTX(ssh_noshell), + dlg_stdcheckbox_handler, + I(offsetof(Config,ssh_no_shell))); ctrl_checkbox(s, "Enable compression", 'e', HELPCTX(ssh_compress), dlg_stdcheckbox_handler, @@ -1502,7 +1506,7 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist, "1 only", 'l', I(0), "1", '1', I(1), "2", '2', I(2), - "2 only", 'n', I(3), NULL); + "2 only", 'y', I(3), NULL); s = ctrl_getset(b, "Connection/SSH", "encryption", "Encryption options"); c = ctrl_draglist(s, "Encryption cipher selection policy:", 's', diff --git a/doc/config.but b/doc/config.but index 4b4271bc..92b479b2 100644 --- a/doc/config.but +++ b/doc/config.but @@ -1,4 +1,4 @@ -\versionid $Id: config.but,v 1.92 2004/10/06 22:31:07 jacob Exp $ +\versionid $Id: config.but,v 1.93 2004/10/13 13:43:11 simon Exp $ \C{config} Configuring PuTTY @@ -1936,6 +1936,27 @@ in a pseudo-terminal. In PuTTY, this is generally only useful for very specialist purposes; although in Plink (see \k{plink}) it is the usual way of working. +\S{config-ssh-noshell} \q{Don't start a shell or command at all} + +\cfg{winhelp-topic}{ssh.noshell} + +If you tick this box, PuTTY will not attempt to run a shell or +command after connecting to the remote server. You might want to use +this option if you are only using the SSH connection for port +forwarding, and your user account on the server does not have the +ability to run a shell. + +This feature is only available in SSH protocol version 2 (since the +version 1 protocol assumes you will always want to run a shell). + +This feature can also be enabled using the \c{-N} command-line +option; see \k{using-cmdline-noshell}. + +If you use this feature in Plink, you will not be able to terminate +the Plink process by any graceful means; the only way to kill it +will be by pressing Control-C or sending a kill signal from another +program. + \S{config-ssh-comp} \q{Enable compression} \cfg{winhelp-topic}{ssh.compress} diff --git a/doc/index.but b/doc/index.but index 806acfd3..efc560dd 100644 --- a/doc/index.but +++ b/doc/index.but @@ -104,6 +104,7 @@ saved sessions from \IM{-T-upper} \c{-T} command-line option \IM{-t} \c{-t} command-line option \IM{-C-upper} \c{-C} command-line option +\IM{-N-upper} \c{-N} command-line option \IM{-1} \c{-1} command-line option \IM{-2} \c{-2} command-line option \IM{-i} \c{-i} command-line option diff --git a/doc/using.but b/doc/using.but index 575603d8..cda9b3b4 100644 --- a/doc/using.but +++ b/doc/using.but @@ -1,4 +1,4 @@ -\versionid $Id: using.but,v 1.33 2004/10/06 22:31:07 jacob Exp $ +\versionid $Id: using.but,v 1.34 2004/10/13 13:43:11 simon Exp $ \C{using} Using PuTTY @@ -694,6 +694,24 @@ configuration box (see \k{config-ssh-pty}). These options are not available in the file transfer tools PSCP and PSFTP. +\S2{using-cmdline-noshell} \I{-N-upper}\c{-N}: suppress starting a +shell or command + +The \c{-N} option prevents PuTTY from attempting to start a shell or +command on the remote server. You might want to use this option if +you are only using the SSH connection for port forwarding, and your +user account on the server does not have the ability to run a shell. + +This feature is only available in SSH protocol version 2 (since the +version 1 protocol assumes you will always want to run a shell). + +This option is equivalent to the \q{Don't start a shell or command +at all} checkbox in the SSH panel of the PuTTY configuration box +(see \k{config-ssh-noshell}). + +These options are not available in the file transfer tools PSCP and +PSFTP. + \S2{using-cmdline-compress} \I{-C-upper}\c{-C}: enable \i{compression} The \c{-C} option enables compression of the data sent across the diff --git a/putty.h b/putty.h index 780b4eb4..827f449c 100644 --- a/putty.h +++ b/putty.h @@ -358,6 +358,7 @@ struct config_tag { int try_ki_auth; int ssh_subsys; /* run a subsystem rather than a command */ int ssh_subsys2; /* fallback to go with remote_cmd2 */ + int ssh_no_shell; /* avoid running a shell */ /* Telnet options */ char termtype[32]; char termspeed[32]; diff --git a/settings.c b/settings.c index 679fab15..b0f223e9 100644 --- a/settings.c +++ b/settings.c @@ -228,6 +228,7 @@ void save_open_settings(void *sesskey, int do_host, Config *cfg) cfg->ssh_cipherlist); write_setting_i(sesskey, "AuthTIS", cfg->try_tis_auth); write_setting_i(sesskey, "AuthKI", cfg->try_ki_auth); + write_setting_i(sesskey, "SshNoShell", cfg->ssh_no_shell); write_setting_i(sesskey, "SshProt", cfg->sshprot); write_setting_i(sesskey, "SSH2DES", cfg->ssh2_des_cbc); write_setting_filename(sesskey, "PublicKeyFile", cfg->keyfile); @@ -490,6 +491,7 @@ void load_open_settings(void *sesskey, int do_host, Config *cfg) gppi(sesskey, "SSH2DES", 0, &cfg->ssh2_des_cbc); gppi(sesskey, "AuthTIS", 0, &cfg->try_tis_auth); gppi(sesskey, "AuthKI", 1, &cfg->try_ki_auth); + gppi(sesskey, "SshNoShell", 0, &cfg->ssh_no_shell); gppfile(sesskey, "PublicKeyFile", &cfg->keyfile); gpps(sesskey, "RemoteCommand", "", cfg->remote_cmd, sizeof(cfg->remote_cmd)); diff --git a/ssh.c b/ssh.c index e8d24313..8356a075 100644 --- a/ssh.c +++ b/ssh.c @@ -5612,43 +5612,47 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) * point; there's no need to send SERVICE_REQUEST. */ - /* - * So now create a channel with a session in it. - */ ssh->channels = newtree234(ssh_channelcmp); - ssh->mainchan = snew(struct ssh_channel); - ssh->mainchan->ssh = ssh; - ssh->mainchan->localid = alloc_channel_id(ssh); - ssh2_pkt_init(ssh, SSH2_MSG_CHANNEL_OPEN); - ssh2_pkt_addstring(ssh, "session"); - ssh2_pkt_adduint32(ssh, ssh->mainchan->localid); - ssh->mainchan->v.v2.locwindow = OUR_V2_WINSIZE; - ssh2_pkt_adduint32(ssh, ssh->mainchan->v.v2.locwindow);/* our window size */ - ssh2_pkt_adduint32(ssh, 0x4000UL); /* our max pkt size */ - ssh2_pkt_send(ssh); - crWaitUntilV(ispkt); - if (ssh->pktin.type != SSH2_MSG_CHANNEL_OPEN_CONFIRMATION) { - bombout(("Server refused to open a session")); - crStopV; - /* FIXME: error data comes back in FAILURE packet */ - } - if (ssh_pkt_getuint32(ssh) != ssh->mainchan->localid) { - bombout(("Server's channel confirmation cited wrong channel")); - crStopV; - } - ssh->mainchan->remoteid = ssh_pkt_getuint32(ssh); - ssh->mainchan->type = CHAN_MAINSESSION; - ssh->mainchan->closes = 0; - ssh->mainchan->v.v2.remwindow = ssh_pkt_getuint32(ssh); - ssh->mainchan->v.v2.remmaxpkt = ssh_pkt_getuint32(ssh); - bufchain_init(&ssh->mainchan->v.v2.outbuffer); - add234(ssh->channels, ssh->mainchan); - logevent("Opened channel for session"); + + /* + * Create the main session channel. + */ + if (!ssh->cfg.ssh_no_shell) { + ssh->mainchan = snew(struct ssh_channel); + ssh->mainchan->ssh = ssh; + ssh->mainchan->localid = alloc_channel_id(ssh); + ssh2_pkt_init(ssh, SSH2_MSG_CHANNEL_OPEN); + ssh2_pkt_addstring(ssh, "session"); + ssh2_pkt_adduint32(ssh, ssh->mainchan->localid); + ssh->mainchan->v.v2.locwindow = OUR_V2_WINSIZE; + ssh2_pkt_adduint32(ssh, ssh->mainchan->v.v2.locwindow);/* our window size */ + ssh2_pkt_adduint32(ssh, 0x4000UL); /* our max pkt size */ + ssh2_pkt_send(ssh); + crWaitUntilV(ispkt); + if (ssh->pktin.type != SSH2_MSG_CHANNEL_OPEN_CONFIRMATION) { + bombout(("Server refused to open a session")); + crStopV; + /* FIXME: error data comes back in FAILURE packet */ + } + if (ssh_pkt_getuint32(ssh) != ssh->mainchan->localid) { + bombout(("Server's channel confirmation cited wrong channel")); + crStopV; + } + ssh->mainchan->remoteid = ssh_pkt_getuint32(ssh); + ssh->mainchan->type = CHAN_MAINSESSION; + ssh->mainchan->closes = 0; + ssh->mainchan->v.v2.remwindow = ssh_pkt_getuint32(ssh); + ssh->mainchan->v.v2.remmaxpkt = ssh_pkt_getuint32(ssh); + bufchain_init(&ssh->mainchan->v.v2.outbuffer); + add234(ssh->channels, ssh->mainchan); + logevent("Opened channel for session"); + } else + ssh->mainchan = NULL; /* * Potentially enable X11 forwarding. */ - if (ssh->cfg.x11_forward) { + if (ssh->mainchan && ssh->cfg.x11_forward) { char proto[20], data[64]; logevent("Requesting X11 forwarding"); ssh->x11auth = x11_invent_auth(proto, sizeof(proto), @@ -5861,7 +5865,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) /* * Potentially enable agent forwarding. */ - if (ssh->cfg.agentfwd && agent_exists()) { + if (ssh->mainchan && ssh->cfg.agentfwd && agent_exists()) { logevent("Requesting OpenSSH-style agent forwarding"); ssh2_pkt_init(ssh, SSH2_MSG_CHANNEL_REQUEST); ssh2_pkt_adduint32(ssh, ssh->mainchan->remoteid); @@ -5897,7 +5901,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) /* * Now allocate a pty for the session. */ - if (!ssh->cfg.nopty) { + if (ssh->mainchan && !ssh->cfg.nopty) { /* Unpick the terminal-speed string. */ /* XXX perhaps we should allow no speeds to be sent. */ ssh->ospeed = 38400; ssh->ispeed = 38400; /* last-resort defaults */ @@ -5954,7 +5958,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) * this twice if the config data has provided a second choice * of command. */ - while (1) { + if (ssh->mainchan) while (1) { int subsys; char *cmd; @@ -6028,7 +6032,8 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) */ if (ssh->ldisc) ldisc_send(ssh->ldisc, NULL, 0, 0);/* cause ldisc to notice changes */ - ssh->send_ok = 1; + if (ssh->mainchan) + ssh->send_ok = 1; while (1) { crReturnV; s->try_send = FALSE; @@ -6171,8 +6176,10 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) /* * See if that was the last channel left open. + * (This is only our termination condition if we're + * not running in -N mode.) */ - if (count234(ssh->channels) == 0) { + if (!ssh->cfg.ssh_no_shell && count234(ssh->channels) == 0) { logevent("All channels closed. Disconnecting"); #if 0 /* @@ -6452,7 +6459,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) bombout(("Strange packet received: type %d", ssh->pktin.type)); crStopV; } - } else { + } else if (ssh->mainchan) { /* * We have spare data. Add it to the channel buffer. */ @@ -6772,7 +6779,7 @@ static void ssh_size(void *handle, int width, int height) PKT_INT, ssh->term_height, PKT_INT, ssh->term_width, PKT_INT, 0, PKT_INT, 0, PKT_END); - } else { + } else if (ssh->mainchan) { ssh2_pkt_init(ssh, SSH2_MSG_CHANNEL_REQUEST); ssh2_pkt_adduint32(ssh, ssh->mainchan->remoteid); ssh2_pkt_addstring(ssh, "window-change"); @@ -6834,7 +6841,7 @@ static void ssh_special(void *handle, Telnet_Special code) } if (ssh->version == 1) { send_packet(ssh, SSH1_CMSG_EOF, PKT_END); - } else { + } else if (ssh->mainchan) { ssh2_pkt_init(ssh, SSH2_MSG_CHANNEL_EOF); ssh2_pkt_adduint32(ssh, ssh->mainchan->remoteid); ssh2_pkt_send(ssh); @@ -6856,7 +6863,7 @@ static void ssh_special(void *handle, Telnet_Special code) || ssh->state == SSH_STATE_PREPACKET) return; if (ssh->version == 1) { logevent("Unable to send BREAK signal in SSH1"); - } else { + } else if (ssh->mainchan) { ssh2_pkt_init(ssh, SSH2_MSG_CHANNEL_REQUEST); ssh2_pkt_adduint32(ssh, ssh->mainchan->remoteid); ssh2_pkt_addstring(ssh, "break"); diff --git a/winhelp.h b/winhelp.h index 6b7ca242..508c0e54 100644 --- a/winhelp.h +++ b/winhelp.h @@ -80,6 +80,7 @@ #define WINHELP_CTX_telnet_newline "telnet.newline" #define WINHELP_CTX_rlogin_localuser "rlogin.localuser" #define WINHELP_CTX_ssh_nopty "ssh.nopty" +#define WINHELP_CTX_ssh_noshell "ssh.noshell" #define WINHELP_CTX_ssh_ciphers "ssh.ciphers" #define WINHELP_CTX_ssh_protocol "ssh.protocol" #define WINHELP_CTX_ssh_command "ssh.command"