void *log_init(void *frontend, Conf *conf) { struct LogContext *ctx = snew(struct LogContext); ctx->lgfp = NULL; ctx->state = L_CLOSED; ctx->frontend = frontend; ctx->conf = conf_copy(conf); ctx->logtype = conf_get_int(ctx->conf, CONF_logtype); bufchain_init(&ctx->queue); return ctx; }
void log_reconfig(void *handle, Conf *conf) { struct LogContext *ctx = (struct LogContext *)handle; int reset_logging; if (!filename_equal(conf_get_filename(ctx->conf, CONF_logfilename), conf_get_filename(conf, CONF_logfilename)) || conf_get_int(ctx->conf, CONF_logtype) != conf_get_int(conf, CONF_logtype)) reset_logging = TRUE; else reset_logging = FALSE; if (reset_logging) logfclose(ctx); conf_free(ctx->conf); ctx->conf = conf_copy(conf); ctx->logtype = conf_get_int(ctx->conf, CONF_logtype); if (reset_logging) logfopen(ctx); }
Socket new_connection(SockAddr addr, const char *hostname, int port, int privport, int oobinline, int nodelay, int keepalive, Plug plug, Conf *conf) { static const struct socket_function_table socket_fn_table = { sk_proxy_plug, sk_proxy_close, sk_proxy_write, sk_proxy_write_oob, sk_proxy_write_eof, sk_proxy_flush, sk_proxy_set_frozen, sk_proxy_socket_error, NULL, /* peer_info */ }; static const struct plug_function_table plug_fn_table = { plug_proxy_log, plug_proxy_closing, plug_proxy_receive, plug_proxy_sent, plug_proxy_accepting}; if (conf_get_int(conf, CONF_proxy_type) != PROXY_NONE && proxy_for_destination(addr, hostname, port, conf)) { Proxy_Socket ret; Proxy_Plug pplug; SockAddr proxy_addr; char *proxy_canonical_name; const char *proxy_type; Socket sret; int type; if ((sret = platform_new_connection(addr, hostname, port, privport, oobinline, nodelay, keepalive, plug, conf)) != NULL) return sret; ret = snew(struct Socket_proxy_tag); ret->fn = &socket_fn_table; ret->conf = conf_copy(conf); ret->plug = plug; ret->remote_addr = addr; /* will need to be freed on close */ ret->remote_port = port; ret->error = NULL; ret->pending_flush = 0; ret->pending_eof = 0; ret->freeze = 0; bufchain_init(&ret->pending_input_data); bufchain_init(&ret->pending_output_data); bufchain_init(&ret->pending_oob_output_data); ret->sub_socket = NULL; ret->state = PROXY_STATE_NEW; ret->negotiate = NULL; type = conf_get_int(conf, CONF_proxy_type); if (type == PROXY_HTTP) { ret->negotiate = proxy_http_negotiate; proxy_type = "HTTP"; } else if (type == PROXY_SOCKS4) { ret->negotiate = proxy_socks4_negotiate; proxy_type = "SOCKS 4"; } else if (type == PROXY_SOCKS5) { ret->negotiate = proxy_socks5_negotiate; proxy_type = "SOCKS 5"; } else if (type == PROXY_TELNET) { ret->negotiate = proxy_telnet_negotiate; proxy_type = "Telnet"; } else { ret->error = "Proxy error: Unknown proxy method"; return (Socket)ret; } { char *logmsg = dupprintf("Will use %s proxy at %s:%d to connect" " to %s:%d", proxy_type, conf_get_str(conf, CONF_proxy_host), conf_get_int(conf, CONF_proxy_port), hostname, port); plug_log(plug, 2, NULL, 0, logmsg, 0); sfree(logmsg); } /* create the proxy plug to map calls from the actual * socket into our proxy socket layer */ pplug = snew(struct Plug_proxy_tag); pplug->fn = &plug_fn_table; pplug->proxy_socket = ret; { char *logmsg = dns_log_msg(conf_get_str(conf, CONF_proxy_host), conf_get_int(conf, CONF_addressfamily), "proxy"); plug_log(plug, 2, NULL, 0, logmsg, 0); sfree(logmsg); } /* look-up proxy */ proxy_addr = sk_namelookup(conf_get_str(conf, CONF_proxy_host), &proxy_canonical_name, conf_get_int(conf, CONF_addressfamily)); if (sk_addr_error(proxy_addr) != NULL) { ret->error = "Proxy error: Unable to resolve proxy host name"; sfree(pplug); sk_addr_free(proxy_addr); return (Socket)ret; } sfree(proxy_canonical_name); { char addrbuf[256], *logmsg; sk_getaddr(proxy_addr, addrbuf, lenof(addrbuf)); logmsg = dupprintf("Connecting to %s proxy at %s port %d", proxy_type, addrbuf, conf_get_int(conf, CONF_proxy_port)); plug_log(plug, 2, NULL, 0, logmsg, 0); sfree(logmsg); } /* create the actual socket we will be using, * connected to our proxy server and port. */ ret->sub_socket = sk_new(proxy_addr, conf_get_int(conf, CONF_proxy_port), privport, oobinline, nodelay, keepalive, (Plug)pplug); if (sk_socket_error(ret->sub_socket) != NULL) return (Socket)ret; /* start the proxy negotiation process... */ sk_set_frozen(ret->sub_socket, 0); ret->negotiate(ret, PROXY_CHANGE_NEW); return (Socket)ret; }
/* * Called to set up the pty. * * Returns an error message, or NULL on success. * * Also places the canonical host name into `realhost'. It must be * freed by the caller. */ static const char *pty_init(void *frontend, void **backend_handle, Conf *conf, char *host, int port, char **realhost, int nodelay, int keepalive) { int slavefd; pid_t pid, pgrp; #ifndef NOT_X_WINDOWS /* for Mac OS X native compilation */ long windowid; #endif Pty pty; if (single_pty) { pty = single_pty; assert(pty->conf == NULL); } else { pty = snew(struct pty_tag); pty->master_fd = pty->slave_fd = -1; #ifndef OMIT_UTMP pty_stamped_utmp = FALSE; #endif } pty->frontend = frontend; *backend_handle = NULL; /* we can't sensibly use this, sadly */ pty->conf = conf_copy(conf); pty->term_width = conf_get_int(conf, CONF_width); pty->term_height = conf_get_int(conf, CONF_height); if (pty->master_fd < 0) pty_open_master(pty); /* * Set the backspace character to be whichever of ^H and ^? is * specified by bksp_is_delete. */ { struct termios attrs; tcgetattr(pty->master_fd, &attrs); attrs.c_cc[VERASE] = conf_get_int(conf, CONF_bksp_is_delete) ? '\177' : '\010'; tcsetattr(pty->master_fd, TCSANOW, &attrs); } #ifndef OMIT_UTMP /* * Stamp utmp (that is, tell the utmp helper process to do so), * or not. */ if (pty_utmp_helper_pipe >= 0) { /* if it's < 0, we can't anyway */ if (!conf_get_int(conf, CONF_stamp_utmp)) { close(pty_utmp_helper_pipe); /* just let the child process die */ pty_utmp_helper_pipe = -1; } else { char *location = get_x_display(pty->frontend); int len = strlen(location)+1, pos = 0; /* +1 to include NUL */ while (pos < len) { int ret = write(pty_utmp_helper_pipe, location+pos, len - pos); if (ret < 0) { perror("pterm: writing to utmp helper process"); close(pty_utmp_helper_pipe); /* arrgh, just give up */ pty_utmp_helper_pipe = -1; break; } pos += ret; } } } #endif #ifndef NOT_X_WINDOWS /* for Mac OS X native compilation */ windowid = get_windowid(pty->frontend); #endif /* * Fork and execute the command. */ pid = fork(); if (pid < 0) { perror("fork"); exit(1); } if (pid == 0) { /* * We are the child. */ slavefd = pty_open_slave(pty); if (slavefd < 0) { perror("slave pty: open"); _exit(1); } close(pty->master_fd); noncloexec(slavefd); dup2(slavefd, 0); dup2(slavefd, 1); dup2(slavefd, 2); close(slavefd); setsid(); #ifdef TIOCSCTTY ioctl(0, TIOCSCTTY, 1); #endif pgrp = getpid(); tcsetpgrp(0, pgrp); setpgid(pgrp, pgrp); { int ptyfd = open(pty->name, O_WRONLY, 0); if (ptyfd >= 0) close(ptyfd); } setpgid(pgrp, pgrp); { char *term_env_var = dupprintf("TERM=%s", conf_get_str(conf, CONF_termtype)); putenv(term_env_var); /* We mustn't free term_env_var, as putenv links it into the * environment in place. */ } #ifndef NOT_X_WINDOWS /* for Mac OS X native compilation */ { char *windowid_env_var = dupprintf("WINDOWID=%ld", windowid); putenv(windowid_env_var); /* We mustn't free windowid_env_var, as putenv links it into the * environment in place. */ } #endif { char *key, *val; for (val = conf_get_str_strs(conf, CONF_environmt, NULL, &key); val != NULL; val = conf_get_str_strs(conf, CONF_environmt, key, &key)) { char *varval = dupcat(key, "=", val, NULL); putenv(varval); /* * We must not free varval, since putenv links it * into the environment _in place_. Weird, but * there we go. Memory usage will be rationalised * as soon as we exec anyway. */ } } /* * SIGINT, SIGQUIT and SIGPIPE may have been set to ignored by * our parent, particularly by things like sh -c 'pterm &' and * some window or session managers. SIGCHLD, meanwhile, was * blocked during pt_main() startup. Reverse all this for our * child process. */ putty_signal(SIGINT, SIG_DFL); putty_signal(SIGQUIT, SIG_DFL); putty_signal(SIGPIPE, SIG_DFL); block_signal(SIGCHLD, 0); if (pty_argv) { /* * Exec the exact argument list we were given. */ execvp(pty_argv[0], pty_argv); /* * If that fails, and if we had exactly one argument, pass * that argument to $SHELL -c. * * This arranges that we can _either_ follow 'pterm -e' * with a list of argv elements to be fed directly to * exec, _or_ with a single argument containing a command * to be parsed by a shell (but, in cases of doubt, the * former is more reliable). * * A quick survey of other terminal emulators' -e options * (as of Debian squeeze) suggests that: * * - xterm supports both modes, more or less like this * - gnome-terminal will only accept a one-string shell command * - Eterm, kterm and rxvt will only accept a list of * argv elements (as did older versions of pterm). * * It therefore seems important to support both usage * modes in order to be a drop-in replacement for either * xterm or gnome-terminal, and hence for anyone's * plausible uses of the Debian-style alias * 'x-terminal-emulator'... */ if (pty_argv[1] == NULL) { char *shell = getenv("SHELL"); if (shell) execl(shell, shell, "-c", pty_argv[0], (void *)NULL); } } else { char *shell = getenv("SHELL"); char *shellname; if (conf_get_int(conf, CONF_login_shell)) { char *p = strrchr(shell, '/'); shellname = snewn(2+strlen(shell), char); p = p ? p+1 : shell; sprintf(shellname, "-%s", p); } else shellname = shell; execl(getenv("SHELL"), shellname, (void *)NULL); }
/* * Called to set up the rlogin connection. * * Returns an error message, or NULL on success. * * Also places the canonical host name into `realhost'. It must be * freed by the caller. */ static const char *rlogin_init(void *frontend_handle, void **backend_handle, Conf *conf, char *host, int port, char **realhost, int nodelay, int keepalive) { static const struct plug_function_table fn_table = { rlogin_log, rlogin_closing, rlogin_receive, rlogin_sent, NULL }; SockAddr addr; const char *err; Rlogin rlogin; char *ruser; int addressfamily; char *loghost; rlogin = snew(struct rlogin_tag); rlogin->fn = &fn_table; rlogin->s = NULL; rlogin->closed_on_socket_error = FALSE; rlogin->frontend = frontend_handle; rlogin->term_width = conf_get_int(conf, CONF_width); rlogin->term_height = conf_get_int(conf, CONF_height); rlogin->firstbyte = 1; rlogin->cansize = 0; rlogin->prompt = NULL; rlogin->conf = conf_copy(conf); *backend_handle = rlogin; addressfamily = conf_get_int(conf, CONF_addressfamily); /* * Try to find host. */ { char *buf; buf = dupprintf("Looking up host \"%s\"%s", host, (addressfamily == ADDRTYPE_IPV4 ? " (IPv4)" : (addressfamily == ADDRTYPE_IPV6 ? " (IPv6)" : ""))); logevent(rlogin->frontend, buf); sfree(buf); } addr = name_lookup(host, port, realhost, conf, addressfamily); if ((err = sk_addr_error(addr)) != NULL) { sk_addr_free(addr); return err; } if (port < 0) port = 513; /* default rlogin port */ /* * Open socket. */ rlogin->s = new_connection(addr, *realhost, port, 1, 0, nodelay, keepalive, (Plug) rlogin, conf); if ((err = sk_socket_error(rlogin->s)) != NULL) return err; loghost = conf_get_str(conf, CONF_loghost); if (*loghost) { char *colon; sfree(*realhost); *realhost = dupstr(loghost); colon = strrchr(*realhost, ':'); if (colon) { /* * FIXME: if we ever update this aspect of ssh.c for * IPv6 literal management, this should change in line * with it. */ *colon++ = '\0'; } } /* * Send local username, remote username, terminal type and * terminal speed - unless we don't have the remote username yet, * in which case we prompt for it and may end up deferring doing * anything else until the local prompt mechanism returns. */ if ((ruser = get_remote_username(conf)) != NULL) { rlogin_startup(rlogin, ruser); sfree(ruser); } else { int ret; rlogin->prompt = new_prompts(rlogin->frontend); rlogin->prompt->to_server = TRUE; rlogin->prompt->name = dupstr("Rlogin login name"); add_prompt(rlogin->prompt, dupstr("rlogin username: "), TRUE); ret = get_userpass_input(rlogin->prompt, NULL, 0); if (ret >= 0) { rlogin_startup(rlogin, rlogin->prompt->prompts[0]->result); } } return NULL; }
/* * Called to set up the raw connection. * * Returns an error message, or NULL on success. * * Also places the canonical host name into `realhost'. It must be * freed by the caller. */ static const char *raw_init(void *frontend_handle, void **backend_handle, Conf *conf, const char *host, int port, char **realhost, int nodelay, int keepalive) { static const struct plug_function_table fn_table = { raw_log, raw_closing, raw_receive, raw_sent }; SockAddr addr; const char *err; Raw raw; int addressfamily; char *loghost; raw = snew(struct raw_backend_data); raw->fn = &fn_table; raw->s = NULL; raw->closed_on_socket_error = FALSE; *backend_handle = raw; raw->sent_console_eof = raw->sent_socket_eof = FALSE; raw->bufsize = 0; raw->session_started = FALSE; raw->conf = conf_copy(conf); raw->frontend = frontend_handle; addressfamily = conf_get_int(conf, CONF_addressfamily); /* * Try to find host. */ addr = name_lookup(host, port, realhost, conf, addressfamily, raw->frontend, "main connection"); if ((err = sk_addr_error(addr)) != NULL) { sk_addr_free(addr); return err; } if (port < 0) port = 23; /* default telnet port */ /* * Open socket. */ raw->s = new_connection(addr, *realhost, port, 0, 1, nodelay, keepalive, (Plug) raw, conf); if ((err = sk_socket_error(raw->s)) != NULL) return err; loghost = conf_get_str(conf, CONF_loghost); if (*loghost) { char *colon; sfree(*realhost); *realhost = dupstr(loghost); colon = host_strrchr(*realhost, ':'); if (colon) *colon++ = '\0'; } return NULL; }
Socket *new_connection(SockAddr *addr, const char *hostname, int port, bool privport, bool oobinline, bool nodelay, bool keepalive, Plug *plug, Conf *conf) { if (conf_get_int(conf, CONF_proxy_type) != PROXY_NONE && proxy_for_destination(addr, hostname, port, conf)) { ProxySocket *ret; SockAddr *proxy_addr; char *proxy_canonical_name; const char *proxy_type; Socket *sret; int type; if ((sret = platform_new_connection(addr, hostname, port, privport, oobinline, nodelay, keepalive, plug, conf)) != NULL) return sret; ret = snew(ProxySocket); ret->sock.vt = &ProxySocket_sockvt; ret->plugimpl.vt = &ProxySocket_plugvt; ret->conf = conf_copy(conf); ret->plug = plug; ret->remote_addr = addr; /* will need to be freed on close */ ret->remote_port = port; ret->error = NULL; ret->pending_flush = false; ret->pending_eof = false; ret->freeze = false; bufchain_init(&ret->pending_input_data); bufchain_init(&ret->pending_output_data); bufchain_init(&ret->pending_oob_output_data); ret->sub_socket = NULL; ret->state = PROXY_STATE_NEW; ret->negotiate = NULL; type = conf_get_int(conf, CONF_proxy_type); if (type == PROXY_HTTP) { ret->negotiate = proxy_http_negotiate; proxy_type = "HTTP"; } else if (type == PROXY_SOCKS4) { ret->negotiate = proxy_socks4_negotiate; proxy_type = "SOCKS 4"; } else if (type == PROXY_SOCKS5) { ret->negotiate = proxy_socks5_negotiate; proxy_type = "SOCKS 5"; } else if (type == PROXY_TELNET) { ret->negotiate = proxy_telnet_negotiate; proxy_type = "Telnet"; } else { ret->error = "Proxy error: Unknown proxy method"; return &ret->sock; } { char *logmsg = dupprintf("Will use %s proxy at %s:%d to connect" " to %s:%d", proxy_type, conf_get_str(conf, CONF_proxy_host), conf_get_int(conf, CONF_proxy_port), hostname, port); plug_log(plug, 2, NULL, 0, logmsg, 0); sfree(logmsg); } { char *logmsg = dns_log_msg(conf_get_str(conf, CONF_proxy_host), conf_get_int(conf, CONF_addressfamily), "proxy"); plug_log(plug, 2, NULL, 0, logmsg, 0); sfree(logmsg); } /* look-up proxy */ proxy_addr = sk_namelookup(conf_get_str(conf, CONF_proxy_host), &proxy_canonical_name, conf_get_int(conf, CONF_addressfamily)); if (sk_addr_error(proxy_addr) != NULL) { ret->error = "Proxy error: Unable to resolve proxy host name"; sk_addr_free(proxy_addr); return &ret->sock; } sfree(proxy_canonical_name); { char addrbuf[256], *logmsg; sk_getaddr(proxy_addr, addrbuf, lenof(addrbuf)); logmsg = dupprintf("Connecting to %s proxy at %s port %d", proxy_type, addrbuf, conf_get_int(conf, CONF_proxy_port)); plug_log(plug, 2, NULL, 0, logmsg, 0); sfree(logmsg); } /* create the actual socket we will be using, * connected to our proxy server and port. */ ret->sub_socket = sk_new(proxy_addr, conf_get_int(conf, CONF_proxy_port), privport, oobinline, nodelay, keepalive, &ret->plugimpl); if (sk_socket_error(ret->sub_socket) != NULL) return &ret->sock; /* start the proxy negotiation process... */ sk_set_frozen(ret->sub_socket, 0); ret->negotiate(ret, PROXY_CHANGE_NEW); return &ret->sock; } /* no proxy, so just return the direct socket */ return sk_new(addr, port, privport, oobinline, nodelay, keepalive, plug); }