2 * Unix implementation of SSH connection-sharing IPC setup.
12 #include <sys/types.h>
15 #define DEFINE_PLUG_METHOD_MACROS
22 #define CONNSHARE_SOCKETDIR_PREFIX "/tmp/putty-connshare"
25 * Functions provided by uxnet.c to help connection sharing.
27 SockAddr unix_sock_addr(const char *path);
28 Socket new_unix_listener(SockAddr listenaddr, Plug plug);
30 static char *make_dirname(const char *name, char **parent_out)
32 char *username, *dirname, *parent;
34 username = get_username();
35 parent = dupprintf("%s.%s", CONNSHARE_SOCKETDIR_PREFIX, username);
37 assert(*parent == '/');
39 dirname = dupprintf("%s/%s", parent, name);
49 static char *make_dir_and_check_ours(const char *dirname)
54 * Create the directory. We might have created it before, so
55 * EEXIST is an OK error; but anything else is doom.
57 if (mkdir(dirname, 0700) < 0 && errno != EEXIST)
58 return dupprintf("%s: mkdir: %s", dirname, strerror(errno));
61 * Now check that that directory is _owned by us_ and not writable
62 * by anybody else. This protects us against somebody else
63 * previously having created the directory in a way that's
64 * writable to us, and thus manipulating us into creating the
65 * actual socket in a directory they can see so that they can
66 * connect to it and use our authenticated SSH sessions.
68 if (stat(dirname, &st) < 0)
69 return dupprintf("%s: stat: %s", dirname, strerror(errno));
70 if (st.st_uid != getuid())
71 return dupprintf("%s: directory owned by uid %d, not by us",
73 if ((st.st_mode & 077) != 0)
74 return dupprintf("%s: directory has overgenerous permissions %03o"
75 " (expected 700)", dirname, st.st_mode & 0777);
80 int platform_ssh_share(const char *pi_name, Conf *conf,
81 Plug downplug, Plug upplug, Socket *sock,
82 char **logtext, char **ds_err, char **us_err,
83 int can_upstream, int can_downstream)
85 char *name, *parentdirname, *dirname, *lockname, *sockname, *err;
90 * Transform the platform-independent version of the connection
91 * identifier into something valid for a Unix socket, by escaping
92 * slashes (and, while we're here, any control characters).
98 name = snewn(1+3*strlen(pi_name), char);
100 for (p = pi_name, q = name; *p; p++) {
101 if (*p == '/' || *p == '%' ||
102 (unsigned char)*p < 0x20 || *p == 0x7f) {
103 q += sprintf(q, "%%%02x", (unsigned char)*p);
112 * First, make sure our subdirectory exists. We must create two
113 * levels of directory - the one for this particular connection,
114 * and the containing one for our username.
116 dirname = make_dirname(name, &parentdirname);
117 if ((err = make_dir_and_check_ours(parentdirname)) != NULL) {
120 sfree(parentdirname);
124 sfree(parentdirname);
125 if ((err = make_dir_and_check_ours(dirname)) != NULL) {
133 * Acquire a lock on a file in that directory.
135 lockname = dupcat(dirname, "/lock", (char *)NULL);
136 lockfd = open(lockname, O_CREAT | O_RDWR | O_TRUNC, 0600);
138 *logtext = dupprintf("%s: open: %s", lockname, strerror(errno));
144 if (flock(lockfd, LOCK_EX) < 0) {
145 *logtext = dupprintf("%s: flock(LOCK_EX): %s",
146 lockname, strerror(errno));
154 sockname = dupprintf("%s/socket", dirname);
158 if (can_downstream) {
159 retsock = new_connection(unix_sock_addr(sockname),
160 "", 0, 0, 1, 0, 0, downplug, conf);
161 if (sk_socket_error(retsock) == NULL) {
169 return SHARE_DOWNSTREAM;
172 *ds_err = dupprintf("%s: %s", sockname, sk_socket_error(retsock));
177 retsock = new_unix_listener(unix_sock_addr(sockname), upplug);
178 if (sk_socket_error(retsock) == NULL) {
186 return SHARE_UPSTREAM;
189 *us_err = dupprintf("%s: %s", sockname, sk_socket_error(retsock));
193 /* One of the above clauses ought to have happened. */
194 assert(*logtext || *ds_err || *us_err);
204 void platform_ssh_share_cleanup(const char *name)
206 char *dirname, *filename;
208 dirname = make_dirname(name, NULL);
210 filename = dupcat(dirname, "/socket", (char *)NULL);
214 filename = dupcat(dirname, "/lock", (char *)NULL);
221 * We deliberately _don't_ clean up the parent directory
222 * /tmp/putty-connshare.<username>, because if we leave it around
223 * then it reduces the ability for other users to be a nuisance by
224 * putting their own directory in the way of it.