diff --git a/config.c b/config.c index 67a018fe..09c77d57 100644 --- a/config.c +++ b/config.c @@ -1751,6 +1751,21 @@ void setup_config_box(struct controlbox *b, int midsession, HELPCTX(connection_username), dlg_stdeditbox_handler, I(offsetof(Config,username)), I(sizeof(((Config *)0)->username))); + { + /* We assume the local username is sufficiently stable + * to include on the dialog box. */ + char *user = get_username(); + char *userlabel = dupprintf("Use system username (%s)", user); + sfree(user); + ctrl_radiobuttons(s, "When username is not specified:", 'n', 4, + HELPCTX(connection_username_from_env), + dlg_stdradiobutton_handler, + I(offsetof(Config, username_from_env)), + "Prompt", I(FALSE), + userlabel, I(TRUE), + NULL); + sfree(userlabel); + } s = ctrl_getset(b, "Connection/Data", "term", "Terminal details"); diff --git a/doc/config.but b/doc/config.but index 96f5dbe4..27704ee9 100644 --- a/doc/config.but +++ b/doc/config.but @@ -1788,6 +1788,22 @@ it explicitly every time. (Some Telnet servers don't support this.) In this box you can type that user name. +\S{config-username-from-env} \q{Use of system username} + +\cfg{winhelp-topic}{connection.usernamefromenv} + +When the previous box (\k{config-username}) is left blank, by default, +PuTTY will prompt for a username at the time you make a connection. + +In some environments, such as large corporate networks with \i{single +sign-on}, a more sensible default may be to use the name of the user +logged in to the local operating system (if any). This control allows +you to change the default behaviour. + +The current system username is displayed in the dialog as a +convenience. It is not saved in the configuration; if a saved session +is later used by a different user, that user's name will be used. + \S{config-termtype} \q{\ii{Terminal-type} string} \cfg{winhelp-topic}{connection.termtype} diff --git a/putty.h b/putty.h index 20cff543..b372d4a3 100644 --- a/putty.h +++ b/putty.h @@ -472,6 +472,7 @@ struct config_tag { char ttymodes[768]; /* MODE\tVvalue\0MODE\tA\0\0 */ char environmt[1024]; /* VAR\tvalue\0VAR\tvalue\0\0 */ char username[100]; + int username_from_env; char localusername[100]; int rfc_environ; int passive_telnet; @@ -790,6 +791,7 @@ void random_destroy_seed(void); */ Backend *backend_from_name(const char *name); Backend *backend_from_proto(int proto); +int get_remote_username(Config *cfg, char *user, size_t len); char *save_settings(char *section, Config * cfg); void save_open_settings(void *sesskey, Config *cfg); void load_settings(char *section, Config * cfg); diff --git a/rlogin.c b/rlogin.c index c9e7c5ec..c392fa0a 100644 --- a/rlogin.c +++ b/rlogin.c @@ -182,12 +182,14 @@ static const char *rlogin_init(void *frontend_handle, void **backend_handle, { char z = 0; char *p; + char ruser[sizeof(cfg->username)]; + (void) get_remote_username(cfg, ruser, sizeof(ruser)); sk_write(rlogin->s, &z, 1); sk_write(rlogin->s, cfg->localusername, strlen(cfg->localusername)); sk_write(rlogin->s, &z, 1); - sk_write(rlogin->s, cfg->username, - strlen(cfg->username)); + sk_write(rlogin->s, ruser, + strlen(ruser)); sk_write(rlogin->s, &z, 1); sk_write(rlogin->s, cfg->termtype, strlen(cfg->termtype)); diff --git a/settings.c b/settings.c index 26926769..7ecd5610 100644 --- a/settings.c +++ b/settings.c @@ -75,6 +75,25 @@ Backend *backend_from_proto(int proto) return NULL; } +int get_remote_username(Config *cfg, char *user, size_t len) +{ + if (*cfg->username) { + strncpy(user, cfg->username, len); + user[len-1] = '\0'; + } else { + if (cfg->username_from_env) { + /* Use local username. */ + char *luser = get_username(); + strncpy(user, luser, len); + user[len-1] = '\0'; + sfree(luser); + } else { + *user = '\0'; + } + } + return (*user != '\0'); +} + static void gpps(void *handle, const char *name, const char *def, char *val, int len) { @@ -316,6 +335,7 @@ void save_open_settings(void *sesskey, Config *cfg) write_setting_s(sesskey, "ProxyTelnetCommand", cfg->proxy_telnet_command); wmap(sesskey, "Environment", cfg->environmt, lenof(cfg->environmt)); write_setting_s(sesskey, "UserName", cfg->username); + write_setting_i(sesskey, "UserNameFromEnvironment", cfg->username_from_env); write_setting_s(sesskey, "LocalUserName", cfg->localusername); write_setting_i(sesskey, "NoPTY", cfg->nopty); write_setting_i(sesskey, "Compression", cfg->compression); @@ -584,7 +604,8 @@ void load_open_settings(void *sesskey, Config *cfg) gpps(sesskey, "ProxyTelnetCommand", "connect %host %port\\n", cfg->proxy_telnet_command, sizeof(cfg->proxy_telnet_command)); gppmap(sesskey, "Environment", "", cfg->environmt, lenof(cfg->environmt)); - gpps(sesskey, "UserName", get_username(), cfg->username, sizeof(cfg->username)); + gpps(sesskey, "UserName", "", cfg->username, sizeof(cfg->username)); + gppi(sesskey, "UserNameFromEnvironment", 0, &cfg->username_from_env); gpps(sesskey, "LocalUserName", "", cfg->localusername, sizeof(cfg->localusername)); gppi(sesskey, "NoPTY", 0, &cfg->nopty); diff --git a/ssh.c b/ssh.c index d30626dc..9f2d0111 100644 --- a/ssh.c +++ b/ssh.c @@ -3361,7 +3361,8 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, fflush(stdout); /* FIXME eh? */ { - if (!*ssh->cfg.username) { + if (!get_remote_username(&ssh->cfg, s->username, + sizeof(s->username))) { int ret; /* need not be kept over crReturn */ s->cur_prompt = new_prompts(ssh->frontend); s->cur_prompt->to_server = TRUE; @@ -3386,9 +3387,6 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, memcpy(s->username, s->cur_prompt->prompts[0]->result, lenof(s->username)); free_prompts(s->cur_prompt); - } else { - strncpy(s->username, ssh->cfg.username, sizeof(s->username)); - s->username[sizeof(s->username)-1] = '\0'; } send_packet(ssh, SSH1_CMSG_USER, PKT_STR, s->username, PKT_END); @@ -7295,7 +7293,8 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, * with change_username turned off we don't try to get * it again. */ - } else if (!*ssh->cfg.username) { + } else if (!get_remote_username(&ssh->cfg, s->username, + sizeof(s->username))) { int ret; /* need not be kept over crReturn */ s->cur_prompt = new_prompts(ssh->frontend); s->cur_prompt->to_server = TRUE; @@ -7323,8 +7322,6 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, free_prompts(s->cur_prompt); } else { char *stuff; - strncpy(s->username, ssh->cfg.username, sizeof(s->username)); - s->username[sizeof(s->username)-1] = '\0'; if ((flags & FLAG_VERBOSE) || (flags & FLAG_INTERACTIVE)) { stuff = dupprintf("Using username \"%s\".\r\n", s->username); c_write_str(ssh, stuff); diff --git a/telnet.c b/telnet.c index 4f0a36fe..20ccc83e 100644 --- a/telnet.c +++ b/telnet.c @@ -466,29 +466,33 @@ static void process_subneg(Telnet telnet) b[n++] = *e++; e++; } - if (*telnet->cfg.username) { - b[n++] = var; - b[n++] = 'U'; - b[n++] = 'S'; - b[n++] = 'E'; - b[n++] = 'R'; - b[n++] = value; - e = telnet->cfg.username; - while (*e) - b[n++] = *e++; + { + char user[sizeof(telnet->cfg.username)]; + (void) get_remote_username(&telnet->cfg, user, sizeof(user)); + if (*user) { + b[n++] = var; + b[n++] = 'U'; + b[n++] = 'S'; + b[n++] = 'E'; + b[n++] = 'R'; + b[n++] = value; + e = user; + while (*e) + b[n++] = *e++; + } + b[n++] = IAC; + b[n++] = SE; + telnet->bufsize = sk_write(telnet->s, (char *)b, n); + logbuf = dupprintf("client:\tSB %s IS %s%s%s%s", + telopt(telnet->sb_opt), + *user ? "USER=" : "", + user, + *user ? " " : "", + n == 6 ? "" : + (*telnet->cfg.environmt ? "" : "")); + logevent(telnet->frontend, logbuf); + sfree(logbuf); } - b[n++] = IAC; - b[n++] = SE; - telnet->bufsize = sk_write(telnet->s, (char *)b, n); - logbuf = dupprintf("client:\tSB %s IS %s%s%s%s", - telopt(telnet->sb_opt), - *telnet->cfg.username ? "USER=" : "", - telnet->cfg.username, - *telnet->cfg.username ? " " : "", - n == 6 ? "" : - (*telnet->cfg.environmt ? "" : "")); - logevent(telnet->frontend, logbuf); - sfree(logbuf); } break; } diff --git a/windows/winhelp.h b/windows/winhelp.h index fc0b8370..4a3c6aaa 100644 --- a/windows/winhelp.h +++ b/windows/winhelp.h @@ -1,6 +1,10 @@ /* - * winhelp.h - define Windows Help context names. These match up with - * the \cfg{winhelp-topic} directives in the Halibut source. + * winhelp.h - define Windows Help context names. + * Each definition has the form "winhelp-topic:halibut-topic", where: + * - "winhelp-topic" matches up with the \cfg{winhelp-topic} directives + * in the Halibut source, and is used for WinHelp; + * - "halibut-topic" matches up with the Halibut keywords in the source, + * and is used for HTML Help. */ /* Maximum length for WINHELP_CTX_foo strings */ @@ -70,6 +74,7 @@ #define WINHELP_CTX_connection_termtype "connection.termtype:config-termtype" #define WINHELP_CTX_connection_termspeed "connection.termspeed:config-termspeed" #define WINHELP_CTX_connection_username "connection.username:config-username" +#define WINHELP_CTX_connection_username_from_env "connection.usernamefromenv:config-username-from-env" #define WINHELP_CTX_connection_keepalive "connection.keepalive:config-keepalive" #define WINHELP_CTX_connection_nodelay "connection.nodelay:config-nodelay" #define WINHELP_CTX_connection_ipversion "connection.ipversion:config-address-family"