* called by a name other than "ssh" or "Secure Shell".
*
* SSH2 support by Markus Friedl.
- * Copyright (c) 2000 Markus Friedl. All rights reserved.
+ * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
*/
#include "includes.h"
-RCSID("$OpenBSD: session.c,v 1.86 2001/06/12 16:10:38 markus Exp $");
+RCSID("$OpenBSD: session.c,v 1.111 2001/12/06 18:09:23 stevesk Exp $");
#include "ssh.h"
#include "ssh1.h"
struct Session {
int used;
int self;
- struct passwd *pw;
+ struct passwd *pw;
+ Authctxt *authctxt;
pid_t pid;
/* tty */
char *term;
int row, col, xpixel, ypixel;
char tty[TTYSZ];
/* X11 */
+ int display_number;
char *display;
int screen;
+ char *auth_display[2];
char *auth_proto;
char *auth_data;
int single_connection;
/* func */
Session *session_new(void);
-void session_set_fds(Session *s, int fdin, int fdout, int fderr);
-void session_pty_cleanup(void *session);
-int session_pty_req(Session *s);
-void session_proctitle(Session *s);
-int session_setup_x11fwd(Session *s);
-void session_close(Session *s);
-void do_exec_pty(Session *s, const char *command);
-void do_exec_no_pty(Session *s, const char *command);
-void do_login(Session *s, const char *command);
+void session_set_fds(Session *, int, int, int);
+static void session_pty_cleanup(void *);
+void session_proctitle(Session *);
+int session_setup_x11fwd(Session *);
+void do_exec_pty(Session *, const char *);
+void do_exec_no_pty(Session *, const char *);
+void do_exec(Session *, const char *);
+void do_login(Session *, const char *);
#ifdef LOGIN_NEEDS_UTMPX
-void do_pre_login(Session *s);
+static void do_pre_login(Session *s);
#endif
-void do_child(Session *s, const char *command);
+void do_child(Session *, const char *);
void do_motd(void);
-int check_quietlogin(Session *s, const char *command);
-void xauthfile_cleanup_proc(void *pw);
+int check_quietlogin(Session *, const char *);
-void do_authenticated1(Authctxt *authctxt);
-void do_authenticated2(Authctxt *authctxt);
+static void do_authenticated1(Authctxt *);
+static void do_authenticated2(Authctxt *);
+
+static void session_close(Session *);
+static int session_pty_req(Session *);
/* import */
extern ServerOptions options;
extern int startup_pipe;
extern void destroy_sensitive_data(void);
-/* Local Xauthority file. */
-static char *xauthfile;
-
/* original command from peer. */
-char *original_command = NULL;
+const char *original_command = NULL;
/* data */
#define MAX_SESSIONS 10
Session sessions[MAX_SESSIONS];
#ifdef WITH_AIXAUTHENTICATE
-/* AIX's lastlogin message, set in auth1.c */
char *aixloginmsg;
#endif /* WITH_AIXAUTHENTICATE */
}
#endif
#endif
+#ifdef WITH_AIXAUTHENTICATE
+ /* We don't have a pty yet, so just label the line as "ssh" */
+ if (loginsuccess(authctxt->user,
+ get_canonical_hostname(options.reverse_mapping_check),
+ "ssh", &aixloginmsg) < 0)
+ aixloginmsg = NULL;
+#endif /* WITH_AIXAUTHENTICATE */
+
/* setup the channel layer */
if (!no_port_forwarding_flag && options.allow_tcp_forwarding)
channel_permit_all_opens();
else
do_authenticated1(authctxt);
- /* remote user's local Xauthority file and agent socket */
- if (xauthfile)
- xauthfile_cleanup_proc(authctxt->pw);
+ /* remove agent socket */
if (auth_get_socket_name())
auth_sock_cleanup_proc(authctxt->pw);
-}
-
-/*
- * Remove local Xauthority file.
- */
-void
-xauthfile_cleanup_proc(void *_pw)
-{
- struct passwd *pw = _pw;
- char *p;
-
- debug("xauthfile_cleanup_proc called");
- if (xauthfile != NULL) {
- temporarily_use_uid(pw);
- unlink(xauthfile);
- p = strrchr(xauthfile, '/');
- if (p != NULL) {
- *p = '\0';
- rmdir(xauthfile);
- }
- xfree(xauthfile);
- xauthfile = NULL;
- restore_uid();
- }
+#ifdef KRB4
+ if (options.kerberos_ticket_cleanup)
+ krb4_cleanup_proc(authctxt);
+#endif
+#ifdef KRB5
+ if (options.kerberos_ticket_cleanup)
+ krb5_cleanup_proc(authctxt);
+#endif
}
/*
* terminals are allocated, X11, TCP/IP, and authentication agent forwardings
* are requested, etc.
*/
-void
+static void
do_authenticated1(Authctxt *authctxt)
{
Session *s;
u_int proto_len, data_len, dlen;
s = session_new();
+ s->authctxt = authctxt;
s->pw = authctxt->pw;
/*
if (packet_set_maxsize(packet_get_int()) > 0)
success = 1;
break;
+
+#if defined(AFS) || defined(KRB5)
+ case SSH_CMSG_HAVE_KERBEROS_TGT:
+ if (!options.kerberos_tgt_passing) {
+ verbose("Kerberos TGT passing disabled.");
+ } else {
+ char *kdata = packet_get_string(&dlen);
+ packet_integrity_check(plen, 4 + dlen, type);
+
+ /* XXX - 0x41, see creds_to_radix version */
+ if (kdata[0] != 0x41) {
+#ifdef KRB5
+ krb5_data tgt;
+ tgt.data = kdata;
+ tgt.length = dlen;
+
+ if (auth_krb5_tgt(s->authctxt, &tgt))
+ success = 1;
+ else
+ verbose("Kerberos v5 TGT refused for %.100s", s->authctxt->user);
+#endif /* KRB5 */
+ } else {
+#ifdef AFS
+ if (auth_krb4_tgt(s->authctxt, kdata))
+ success = 1;
+ else
+ verbose("Kerberos v4 TGT refused for %.100s", s->authctxt->user);
+#endif /* AFS */
+ }
+ xfree(kdata);
+ }
+ break;
+#endif /* AFS || KRB5 */
+
+#ifdef AFS
+ case SSH_CMSG_HAVE_AFS_TOKEN:
+ if (!options.afs_token_passing || !k_hasafs()) {
+ verbose("AFS token passing disabled.");
+ } else {
+ /* Accept AFS token. */
+ char *token = packet_get_string(&dlen);
+ packet_integrity_check(plen, 4 + dlen, type);
+
+ if (auth_afs_token(s->authctxt, token))
+ success = 1;
+ else
+ verbose("AFS token refused for %.100s",
+ s->authctxt->user);
+ xfree(token);
+ }
+ break;
+#endif /* AFS */
case SSH_CMSG_EXEC_SHELL:
case SSH_CMSG_EXEC_CMD:
if (type == SSH_CMSG_EXEC_CMD) {
command = packet_get_string(&dlen);
debug("Exec command '%.500s'", command);
- packet_integrity_check(plen, 4 + dlen, type);
+ do_exec(s, command);
+ xfree(command);
} else {
- command = NULL;
- packet_integrity_check(plen, 0, type);
- }
- if (forced_command != NULL) {
- original_command = command;
- command = forced_command;
- debug("Forced command '%.500s'", forced_command);
+ do_exec(s, NULL);
}
- if (s->ttyfd != -1)
- do_exec_pty(s, command);
- else
- do_exec_no_pty(s, command);
- if (command != NULL)
- xfree(command);
+ packet_done();
session_close(s);
return;
session_proctitle(s);
#if defined(USE_PAM)
+ do_pam_session(s->pw->pw_name, NULL);
do_pam_setcred(1);
+ if (is_pam_password_change_required())
+ packet_disconnect("Password change required but no "
+ "TTY available");
#endif /* USE_PAM */
/* Fork the child. */
/* Fork the child. */
if ((pid = fork()) == 0) {
+
/* Child. Reinitialize the log because the pid has changed. */
log_init(__progname, options.log_level, options.log_facility, log_stderr);
-
/* Close the master side of the pseudo tty. */
close(ptyfd);
/* Make the pseudo tty our controlling tty. */
pty_make_controlling_tty(&ttyfd, s->tty);
- /* Redirect stdin from the pseudo tty. */
- if (dup2(ttyfd, fileno(stdin)) < 0)
- error("dup2 stdin failed: %.100s", strerror(errno));
-
- /* Redirect stdout to the pseudo tty. */
- if (dup2(ttyfd, fileno(stdout)) < 0)
- error("dup2 stdin failed: %.100s", strerror(errno));
-
- /* Redirect stderr to the pseudo tty. */
- if (dup2(ttyfd, fileno(stderr)) < 0)
- error("dup2 stdin failed: %.100s", strerror(errno));
+ /* Redirect stdin/stdout/stderr from the pseudo tty. */
+ if (dup2(ttyfd, 0) < 0)
+ error("dup2 stdin: %s", strerror(errno));
+ if (dup2(ttyfd, 1) < 0)
+ error("dup2 stdout: %s", strerror(errno));
+ if (dup2(ttyfd, 2) < 0)
+ error("dup2 stderr: %s", strerror(errno));
/* Close the extra descriptor for the pseudo tty. */
close(ttyfd);
}
#ifdef LOGIN_NEEDS_UTMPX
-void
+static void
do_pre_login(Session *s)
{
socklen_t fromlen;
}
#endif
+/*
+ * This is called to fork and execute a command. If another command is
+ * to be forced, execute that instead.
+ */
+void
+do_exec(Session *s, const char *command)
+{
+ if (forced_command) {
+ original_command = command;
+ command = forced_command;
+ debug("Forced command '%.900s'", command);
+ }
+
+ if (s->ttyfd != -1)
+ do_exec_pty(s, command);
+ else
+ do_exec_no_pty(s, command);
+
+ original_command = NULL;
+}
+
/* administrative, login(1)-like work */
void
do_login(Session *s, const char *command)
check_quietlogin(Session *s, const char *command)
{
char buf[256];
- struct passwd * pw = s->pw;
+ struct passwd *pw = s->pw;
struct stat st;
/* Return 1 if .hushlogin exists or a command given. */
* Sets the value of the given variable in the environment. If the variable
* already exists, its value is overriden.
*/
-void
+static void
child_set_env(char ***envp, u_int *envsizep, const char *name,
const char *value)
{
* Otherwise, it must consist of empty lines, comments (line starts with '#')
* and assignments of the form name=value. No other forms are allowed.
*/
-void
+static void
read_environment_file(char ***env, u_int *envsize,
const char *filename)
{
/*
* Sets any environment variables which have been specified by PAM
*/
-void do_pam_environment(char ***env, int *envsize)
+void do_pam_environment(char ***env, u_int *envsize)
{
char *equals, var_name[512], var_val[512];
char **pam_env;
#endif /* USE_PAM */
#ifdef HAVE_CYGWIN
-void copy_environment(char ***env, int *envsize)
+void copy_environment(char ***env, u_int *envsize)
{
char *equals, var_name[512], var_val[512];
int i;
do_child(Session *s, const char *command)
{
const char *shell, *hostname = NULL, *cp = NULL;
- struct passwd * pw = s->pw;
+ struct passwd *pw = s->pw;
char buf[256];
char cmd[1024];
FILE *f = NULL;
if (options.use_login && command != NULL)
options.use_login = 0;
-#if !defined(USE_PAM) && !defined(HAVE_OSF_SIA)
+#if !defined(HAVE_OSF_SIA)
if (!options.use_login) {
# ifdef HAVE_LOGIN_CAP
if (!login_getcapbool(lc, "ignorenologin", 0) && pw->pw_uid)
exit(254);
}
}
-#endif /* USE_PAM || HAVE_OSF_SIA */
+#endif /* HAVE_OSF_SIA */
/* Set login name, uid, gid, and groups. */
/* Login(1) does this as well, and it needs uid 0 for the "-h"
shell = login_getcapstr(lc, "shell", (char *)shell, (char *)shell);
#endif
-#ifdef AFS
- /* Try to get AFS tokens for the local cell. */
- if (k_hasafs()) {
- char cell[64];
-
- if (k_afs_cell_of_file(pw->pw_dir, cell, sizeof(cell)) == 0)
- krb_afslog(cell, 0);
-
- krb_afslog(0, 0);
- }
-#endif /* AFS */
-
/* Initialize the environment. */
envsize = 100;
env = xmalloc(envsize * sizeof(char *));
child_set_env(&env, &envsize, "TZ", getenv("TZ"));
/* Set custom environment options from RSA authentication. */
- while (custom_environment) {
- struct envstring *ce = custom_environment;
- char *s = ce->s;
- int i;
- for (i = 0; s[i] != '=' && s[i]; i++);
- if (s[i] == '=') {
- s[i] = 0;
- child_set_env(&env, &envsize, s, s + i + 1);
+ if (!options.use_login) {
+ while (custom_environment) {
+ struct envstring *ce = custom_environment;
+ char *s = ce->s;
+ int i;
+ for (i = 0; s[i] != '=' && s[i]; i++)
+ ;
+ if (s[i] == '=') {
+ s[i] = 0;
+ child_set_env(&env, &envsize, s, s + i + 1);
+ }
+ custom_environment = ce->next;
+ xfree(ce->s);
+ xfree(ce);
}
- custom_environment = ce->next;
- xfree(ce->s);
- xfree(ce);
}
snprintf(buf, sizeof buf, "%.50s %d %d",
child_set_env(&env, &envsize, "KRB5CCNAME", cp);
read_environment_file(&env, &envsize, "/etc/environment");
#endif
-
#ifdef KRB4
- {
- extern char *ticket;
-
- if (ticket)
- child_set_env(&env, &envsize, "KRBTKFILE", ticket);
- }
-#endif /* KRB4 */
-
+ if (s->authctxt->krb4_ticket_file)
+ child_set_env(&env, &envsize, "KRBTKFILE",
+ s->authctxt->krb4_ticket_file);
+#endif
+#ifdef KRB5
+ if (s->authctxt->krb5_ticket_file)
+ child_set_env(&env, &envsize, "KRB5CCNAME",
+ s->authctxt->krb5_ticket_file);
+#endif
#ifdef USE_PAM
/* Pull in any environment variables that may have been set by PAM. */
do_pam_environment(&env, &envsize);
#endif /* USE_PAM */
- if (xauthfile)
- child_set_env(&env, &envsize, "XAUTHORITY", xauthfile);
if (auth_get_socket_name() != NULL)
child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME,
auth_get_socket_name());
for (i = 3; i < 64; i++)
close(i);
+ /*
+ * Must take new environment into use so that .ssh/rc, /etc/sshrc and
+ * xauth are run in the proper environment.
+ */
+ environ = env;
+
+#ifdef AFS
+ /* Try to get AFS tokens for the local cell. */
+ if (k_hasafs()) {
+ char cell[64];
+
+ if (k_afs_cell_of_file(pw->pw_dir, cell, sizeof(cell)) == 0)
+ krb_afslog(cell, 0);
+
+ krb_afslog(0, 0);
+ }
+#endif /* AFS */
+
/* Change current directory to the user\'s home directory. */
if (chdir(pw->pw_dir) < 0) {
fprintf(stderr, "Could not chdir to home directory %s: %s\n",
- pw->pw_dir, strerror(errno));
+ pw->pw_dir, strerror(errno));
#ifdef HAVE_LOGIN_CAP
if (login_getcapbool(lc, "requirehome", 0))
exit(1);
#endif
}
- /*
- * Must take new environment into use so that .ssh/rc, /etc/sshrc and
- * xauth are run in the proper environment.
- */
- environ = env;
-
/*
* Run $HOME/.ssh/rc, /etc/sshrc, or xauth (whichever is found first
* in this order).
_PATH_SSH_SYSTEM_RC);
} else if (do_xauth && options.xauth_location != NULL) {
/* Add authority data to .Xauthority if appropriate. */
- char *screen = strchr(s->display, ':');
-
if (debug_flag) {
fprintf(stderr,
"Running %.100s add "
"%.100s %.100s %.100s\n",
- options.xauth_location, s->display,
+ options.xauth_location, s->auth_display[0],
s->auth_proto, s->auth_data);
- if (screen != NULL)
+ if (s->auth_display[1])
fprintf(stderr,
- "Adding %.*s/unix%s %s %s\n",
- (int)(screen - s->display),
- s->display, screen,
+ "add %.100s %.100s %.100s\n",
+ s->auth_display[1],
s->auth_proto, s->auth_data);
}
snprintf(cmd, sizeof cmd, "%s -q -",
options.xauth_location);
f = popen(cmd, "w");
if (f) {
- fprintf(f, "add %s %s %s\n", s->display,
- s->auth_proto, s->auth_data);
- if (screen != NULL)
- fprintf(f, "add %.*s/unix%s %s %s\n",
- (int)(screen - s->display),
- s->display, screen,
- s->auth_proto,
+ fprintf(f, "add %s %s %s\n",
+ s->auth_display[0], s->auth_proto,
+ s->auth_data);
+ if (s->auth_display[1])
+ fprintf(f, "add %s %s %s\n",
+ s->auth_display[1], s->auth_proto,
s->auth_data);
pclose(f);
} else {
if (!options.use_login) {
char buf[256];
- /*
- * Check for mail if we have a tty and it was enabled
- * in server options.
- */
- if (s->ttyfd != -1 && options.check_mail) {
- char *mailbox;
- struct stat mailstat;
-
- mailbox = getenv("MAIL");
- if (mailbox != NULL) {
- if (stat(mailbox, &mailstat) != 0 ||
- mailstat.st_size == 0)
- printf("No mail.\n");
- else if (mailstat.st_mtime < mailstat.st_atime)
- printf("You have mail.\n");
- else
- printf("You have new mail.\n");
- }
- }
/* Start the shell. Set initial character to '-'. */
buf[0] = '-';
- strncpy(buf + 1, cp, sizeof(buf) - 1);
- buf[sizeof(buf) - 1] = 0;
+ strlcpy(buf + 1, cp, sizeof(buf) - 1);
/* Execute the shell. */
argv[0] = buf;
#ifdef LOGIN_NEEDS_TERM
s->term? s->term : "unknown",
#endif
- "-p", "-f", "--", pw->pw_name, NULL);
+ "-p", "-f", "--", pw->pw_name, (char *)NULL);
/* Login couldn't be executed, die. */
return NULL;
}
-void
+static void
session_dump(void)
{
int i;
}
int
-session_open(int chanid)
+session_open(Authctxt *authctxt, int chanid)
{
Session *s = session_new();
debug("session_open: channel %d", chanid);
error("no more sessions");
return 0;
}
- s->pw = auth_get_user();
+ s->authctxt = authctxt;
+ s->pw = authctxt->pw;
if (s->pw == NULL)
fatal("no user for session %d", s->self);
debug("session_open: session %d: link with channel %d", s->self, chanid);
return 1;
}
-Session *
+static Session *
session_by_channel(int id)
{
int i;
return NULL;
}
-Session *
+static Session *
session_by_pid(pid_t pid)
{
int i;
return NULL;
}
-int
+static int
session_window_change_req(Session *s)
{
s->col = packet_get_int();
return 1;
}
-int
+static int
session_pty_req(Session *s)
{
u_int len;
return 1;
}
-int
+static int
session_subsystem_req(Session *s)
{
+ struct stat st;
u_int len;
int success = 0;
- char *subsys = packet_get_string(&len);
+ char *cmd, *subsys = packet_get_string(&len);
int i;
packet_done();
log("subsystem request for %s", subsys);
for (i = 0; i < options.num_subsystems; i++) {
- if(strcmp(subsys, options.subsystem_name[i]) == 0) {
- debug("subsystem: exec() %s", options.subsystem_command[i]);
+ if (strcmp(subsys, options.subsystem_name[i]) == 0) {
+ cmd = options.subsystem_command[i];
+ if (stat(cmd, &st) < 0) {
+ error("subsystem: cannot stat %s: %s", cmd,
+ strerror(errno));
+ break;
+ }
+ debug("subsystem: exec() %s", cmd);
s->is_subsystem = 1;
- do_exec_no_pty(s, options.subsystem_command[i]);
+ do_exec(s, cmd);
success = 1;
}
}
if (!success)
- log("subsystem request for %s failed, subsystem not found", subsys);
+ log("subsystem request for %s failed, subsystem not found",
+ subsys);
xfree(subsys);
return success;
}
-int
+static int
session_x11_req(Session *s)
{
int success;
return success;
}
-int
+static int
session_shell_req(Session *s)
{
- /* if forced_command == NULL, the shell is execed */
- char *shell = forced_command;
packet_done();
- if (s->ttyfd == -1)
- do_exec_no_pty(s, shell);
- else
- do_exec_pty(s, shell);
+ do_exec(s, NULL);
return 1;
}
-int
+static int
session_exec_req(Session *s)
{
u_int len;
char *command = packet_get_string(&len);
packet_done();
- if (forced_command) {
- original_command = command;
- command = forced_command;
- debug("Forced command '%.500s'", forced_command);
- }
- if (s->ttyfd == -1)
- do_exec_no_pty(s, command);
- else
- do_exec_pty(s, command);
- if (forced_command == NULL)
- xfree(command);
+ do_exec(s, command);
+ xfree(command);
return 1;
}
-int
+static int
session_auth_agent_req(Session *s)
{
static int called = 0;
* Function to perform pty cleanup. Also called if we get aborted abnormally
* (e.g., due to a dropped connection).
*/
-void
+static void
session_pty_cleanup(void *session)
{
Session *s = session;
*/
if (close(s->ptymaster) < 0)
error("close(s->ptymaster): %s", strerror(errno));
+
+ /* unlink pty from session */
+ s->ttyfd = -1;
}
-void
+static void
session_exit_message(Session *s, int status)
{
Channel *c;
s->chanid = -1;
}
-void
+static void
session_close(Session *s)
{
debug("session_close: session %d pid %d", s->self, s->pid);
xfree(s->term);
if (s->display)
xfree(s->display);
+ if (s->auth_display[0])
+ xfree(s->auth_display[0]);
+ if (s->auth_display[1])
+ xfree(s->auth_display[1]);
if (s->auth_data)
xfree(s->auth_data);
if (s->auth_proto)
{
Session *s = session_by_pid(pid);
if (s == NULL) {
- debug("session_close_by_pid: no session for pid %d", s->pid);
+ debug("session_close_by_pid: no session for pid %d", pid);
return;
}
if (s->chanid != -1)
{
Session *s = session_by_channel(id);
if (s == NULL) {
- debug("session_close_by_channel: no session for channel %d", id);
+ debug("session_close_by_channel: no session for id %d", id);
return;
}
- /* disconnect channel */
+ debug("session_close_by_channel: channel %d child %d", id, s->pid);
+ if (s->pid != 0) {
+ debug("session_close_by_channel: channel %d: has child", id);
+ /*
+ * delay detach of session, but release pty, since
+ * the fd's to the child are already closed
+ */
+ if (s->ttyfd != -1) {
+ fatal_remove_cleanup(session_pty_cleanup, (void *)s);
+ session_pty_cleanup(s);
+ }
+ return;
+ }
+ /* detach by removing callback */
channel_cancel_cleanup(s->chanid);
s->chanid = -1;
+ session_close(s);
+}
- debug("session_close_by_channel: channel %d kill %d", id, s->pid);
- if (s->pid == 0) {
- /* close session immediately */
- session_close(s);
- } else {
- /* notify child, delay session cleanup */
- if (kill(s->pid, (s->ttyfd == -1) ? SIGTERM : SIGHUP) < 0)
- error("session_close_by_channel: kill %d: %s",
- s->pid, strerror(errno));
+void
+session_destroy_all(void)
+{
+ int i;
+ for(i = 0; i < MAX_SESSIONS; i++) {
+ Session *s = &sessions[i];
+ if (s->used)
+ session_close(s);
}
}
-char *
+static char *
session_tty_list(void)
{
static char buf[1024];
int
session_setup_x11fwd(Session *s)
{
- int fd;
struct stat st;
+ char display[512], auth_display[512];
+ char hostname[MAXHOSTNAMELEN];
if (no_x11_forwarding_flag) {
packet_send_debug("X11 forwarding disabled in user configuration file.");
packet_send_debug("No xauth program; cannot forward with spoofing.");
return 0;
}
- if (s->display != NULL || xauthfile != NULL) {
- debug("X11 display already set.");
+ if (options.use_login) {
+ packet_send_debug("X11 forwarding disabled; "
+ "not compatible with UseLogin=yes.");
return 0;
}
- xauthfile = xmalloc(MAXPATHLEN);
- strlcpy(xauthfile, "/tmp/ssh-XXXXXXXX", MAXPATHLEN);
- temporarily_use_uid(s->pw);
- if (mkdtemp(xauthfile) == NULL) {
- error("private X11 dir: mkdtemp %s failed: %s",
- xauthfile, strerror(errno));
- restore_uid();
- xfree(xauthfile);
- xauthfile = NULL;
+ if (s->display != NULL) {
+ debug("X11 display already set.");
return 0;
}
- strlcat(xauthfile, "/cookies", MAXPATHLEN);
- fd = open(xauthfile, O_RDWR|O_CREAT|O_EXCL, 0600);
- if (fd >= 0)
- close(fd);
- restore_uid();
- s->display = x11_create_display_inet(s->screen, options.x11_display_offset);
- if (s->display == NULL) {
- xauthfile_cleanup_proc(s->pw);
+ s->display_number = x11_create_display_inet(options.x11_display_offset,
+ options.gateway_ports);
+ if (s->display_number == -1) {
+ debug("x11_create_display_inet failed.");
return 0;
}
- fatal_add_cleanup(xauthfile_cleanup_proc, s->pw);
+
+ /* Set up a suitable value for the DISPLAY variable. */
+ if (gethostname(hostname, sizeof(hostname)) < 0)
+ fatal("gethostname: %.100s", strerror(errno));
+ /*
+ * auth_display must be used as the displayname when the
+ * authorization entry is added with xauth(1). This will be
+ * different than the DISPLAY string for localhost displays.
+ */
+ s->auth_display[1] = NULL;
+ if (!options.gateway_ports) {
+ struct utsname uts;
+
+ snprintf(display, sizeof display, "localhost:%d.%d",
+ s->display_number, s->screen);
+ snprintf(auth_display, sizeof auth_display, "%.400s/unix:%d.%d",
+ hostname, s->display_number, s->screen);
+ s->display = xstrdup(display);
+ s->auth_display[0] = xstrdup(auth_display);
+ /*
+ * Xlib may use gethostbyname() or uname() hostname to
+ * look up authorization data for FamilyLocal; see:
+ * xc/lib/xtrans/Xtrans.c:TRANS(GetHostname)
+ * We just add authorization entries with both
+ * hostname and nodename if they are different.
+ */
+ if (uname(&uts) == -1)
+ fatal("uname: %.100s", strerror(errno));
+ if (strcmp(hostname, uts.nodename) != 0) {
+ snprintf(auth_display, sizeof auth_display,
+ "%.400s/unix:%d.%d", uts.nodename,
+ s->display_number, s->screen);
+ s->auth_display[1] = xstrdup(auth_display);
+ }
+ } else {
+#ifdef IPADDR_IN_DISPLAY
+ struct hostent *he;
+ struct in_addr my_addr;
+
+ he = gethostbyname(hostname);
+ if (he == NULL) {
+ error("Can't get IP address for X11 DISPLAY.");
+ packet_send_debug("Can't get IP address for X11 DISPLAY.");
+ return 0;
+ }
+ memcpy(&my_addr, he->h_addr_list[0], sizeof(struct in_addr));
+ snprintf(display, sizeof display, "%.50s:%d.%d", inet_ntoa(my_addr),
+ s->display_number, s->screen);
+#else
+ snprintf(display, sizeof display, "%.400s:%d.%d", hostname,
+ s->display_number, s->screen);
+#endif
+ s->display = xstrdup(display);
+ s->auth_display[0] = xstrdup(display);
+ }
+
return 1;
}
-void
+static void
do_authenticated2(Authctxt *authctxt)
{
- server_loop2();
+ server_loop2(authctxt);
}