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