1 From 885edd4c7c2e7f77debc253b1d097387bed0d96b Mon Sep 17 00:00:00 2001
2 From: oracle <solaris@oracle.com>
3 Date: Tue, 22 Dec 2015 17:12:50 -0800
4 Subject: [PATCH 20/36] Per-session xauthfile
5
6 This patch is to fix a X11 connection failure when a user's home directory
7 is read-only.
8
9 We have contributed back this fix to the OpenSSH upstream community. For
10 more information, see https://bugzilla.mindrot.org/show_bug.cgi?id=2440
11 In the future, if this fix is accepted by the upsteam in a later release, we
12 will remove this patch when we upgrade to that release.
13 ---
14 session.c | 129 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
15 session.h | 3 ++
16 2 files changed, 132 insertions(+)
17
18 diff --git a/session.c b/session.c
19 index 5a64715..ab0ac1c 100644
20 --- a/session.c
21 +++ b/session.c
22 @@ -62,6 +62,10 @@
23 #include <unistd.h>
24 #include <limits.h>
25
26 +#ifdef PER_SESSION_XAUTHFILE
27 +#include <libgen.h>
28 +#endif
29 +
30 #include "openbsd-compat/sys-queue.h"
31 #include "xmalloc.h"
32 #include "ssh.h"
33 @@ -132,6 +136,11 @@ static void do_authenticated2(Authctxt *);
34
35 static int session_pty_req(Session *);
36
37 +#ifdef PER_SESSION_XAUTHFILE
38 +void session_xauthfile_cleanup(Session *);
39 +void cleanup_all_session_xauthfile();
40 +#endif
41 +
42 /* import */
43 extern ServerOptions options;
44 extern char *__progname;
45 @@ -1218,6 +1227,11 @@ do_setup_env(Session *s, const char *shell)
46 if (getenv("TZ"))
47 child_set_env(&env, &envsize, "TZ", getenv("TZ"));
48
49 +#ifdef PER_SESSION_XAUTHFILE
50 + if (s->auth_file != NULL)
51 + child_set_env(&env, &envsize, "XAUTHORITY", s->auth_file);
52 +#endif
53 +
54 /* Set custom environment options from RSA authentication. */
55 if (!options.use_login) {
56 while (custom_environment) {
57 @@ -2170,6 +2184,11 @@ session_x11_req(Session *s)
58 {
59 int success;
60
61 +#ifdef PER_SESSION_XAUTHFILE
62 + int fd;
63 + char xauthdir[] = "/tmp/ssh-xauth-XXXXXX";
64 +#endif
65 +
66 if (s->auth_proto != NULL || s->auth_data != NULL) {
67 error("session_x11_req: session %d: "
68 "x11 forwarding already active", s->self);
69 @@ -2181,13 +2200,71 @@ session_x11_req(Session *s)
70 s->screen = packet_get_int();
71 packet_check_eom();
72
73 +#ifdef PER_SESSION_XAUTHFILE
74 + /*
75 + * Create per session X authority file in the /tmp directory.
76 + *
77 + * If mkdtemp() or open() fails then s->auth_file remains NULL which
78 + * means that we won't set XAUTHORITY variable in child's environment
79 + * and xauth(1) will use the default location for the authority file.
80 + */
81 + if (mkdtemp(xauthdir) != NULL) {
82 + s->auth_file = xmalloc(MAXPATHLEN);
83 + if (snprintf(s->auth_file, MAXPATHLEN, "%s/xauthfile",
84 + xauthdir) >= MAXPATHLEN) {
85 + error("temporary X authority file name was too long "
86 + "for the buffer allocated");
87 + success = 0;
88 + goto out;
89 + }
90 + /*
91 + * we don't want that "creating new authority file" message to
92 + * be printed by xauth(1) so we must create that file
93 + * beforehand.
94 + */
95 + if ((fd = open(s->auth_file, O_CREAT | O_EXCL | O_RDONLY,
96 + S_IRUSR | S_IWUSR)) == -1) {
97 + error("failed to create the temporary X authority "
98 + "file %s: %.100s; will use the default one",
99 + s->auth_file, strerror(errno));
100 + free(s->auth_file);
101 + s->auth_file = NULL;
102 + if (rmdir(xauthdir) == -1) {
103 + error("cannot remove xauth directory "
104 + "%s: %.100s", xauthdir, strerror(errno));
105 + }
106 + } else {
107 + if (close(fd) != 0) {
108 + error("close() failed on temporary X authority "
109 + "file: %s", strerror(errno));
110 + success = 0;
111 + goto out;
112 + }
113 + debug("temporary X authority file %s created",
114 + s->auth_file);
115 + debug("session number = %d", s->self);
116 + }
117 + } else {
118 + error("failed to create a directory for the temporary X "
119 + "authority file: %.100s; will use the default xauth file",
120 + strerror(errno));
121 + }
122 +#endif
123 +
124 success = session_setup_x11fwd(s);
125 +
126 +out:
127 if (!success) {
128 free(s->auth_proto);
129 free(s->auth_data);
130 s->auth_proto = NULL;
131 s->auth_data = NULL;
132 +#ifdef PER_SESSION_XAUTHFILE
133 + free(s->auth_file);
134 + s->auth_file = NULL;
135 +#endif
136 }
137 +
138 return success;
139 }
140
141 @@ -2378,6 +2455,51 @@ session_pty_cleanup(Session *s)
142 PRIVSEP(session_pty_cleanup2(s));
143 }
144
145 +#ifdef PER_SESSION_XAUTHFILE
146 +/*
147 + * We use a different temporary X authority file per session so we should
148 + * remove those files when cleanup_exit() is called.
149 + */
150 +void
151 +session_xauthfile_cleanup(Session *s)
152 +{
153 + if (s == NULL || s->auth_file == NULL) {
154 + return;
155 + }
156 +
157 + debug("session_xauthfile_cleanup: session %d removing %s", s->self,
158 + s->auth_file);
159 +
160 + if (unlink(s->auth_file) == -1) {
161 + error("session_xauthfile_cleanup: cannot remove xauth file "
162 + "%s: %.100s", s->auth_file, strerror(errno));
163 + return;
164 + }
165 +
166 + /* dirname() will modify s->auth_file but that's ok */
167 + if (rmdir(dirname(s->auth_file)) == -1) {
168 + error("session_xauthfile_cleanup: "
169 + "cannot remove xauth directory %s: %.100s",
170 + s->auth_file, strerror(errno));
171 + return;
172 + }
173 + free(s->auth_file);
174 + s->auth_file = NULL;
175 +}
176 +
177 +/*
178 + * This is called by do_cleanup() when cleanup_exit() is called.
179 + */
180 +void
181 +cleanup_all_session_xauthfile()
182 +{
183 + int i;
184 + for (i = 0; i < sessions_nalloc; i++) {
185 + session_xauthfile_cleanup(&sessions[i]);
186 + }
187 +}
188 +#endif
189 +
190 static char *
191 sig2name(int sig)
192 {
193 @@ -2512,6 +2634,9 @@ session_close(Session *s)
194 free(s->auth_display);
195 free(s->auth_data);
196 free(s->auth_proto);
197 +#ifdef PER_SESSION_XAUTHFILE
198 + session_xauthfile_cleanup(s);
199 +#endif
200 free(s->subsys);
201 if (s->env != NULL) {
202 for (i = 0; i < s->num_env; i++) {
203 @@ -2763,6 +2888,10 @@ do_cleanup(Authctxt *authctxt)
204 /* remove agent socket */
205 auth_sock_cleanup_proc(authctxt->pw);
206
207 +#ifdef PER_SESSION_XAUTHFILE
208 + cleanup_all_session_xauthfile();
209 +#endif
210 +
211 /*
212 * Cleanup ptys/utmp only if privsep is disabled,
213 * or if running in monitor.
214 diff --git a/session.h b/session.h
215 index 6a2f35e..276cd04 100644
216 --- a/session.h
217 +++ b/session.h
218 @@ -49,6 +49,9 @@ struct Session {
219 char *auth_display;
220 char *auth_proto;
221 char *auth_data;
222 +#ifdef PER_SESSION_XAUTHFILE
223 + char *auth_file; /* xauth(1) authority file */
224 +#endif
225 int single_connection;
226
227 /* proto 2 */
228 --
229 2.5.4 (Apple Git-61)
230