+ {
+ unsigned char saltbuf[SALT_SIZE];
+ char *saltname;
+ int saltfd, i, ret;
+
+ saltname = dupprintf("%s/%s", parentdirname, SALT_FILENAME);
+ saltfd = open(saltname, O_RDONLY);
+ if (saltfd < 0) {
+ char *tmpname;
+ int pid;
+
+ if (errno != ENOENT) {
+ *logtext = dupprintf("%s: open: %s", saltname,
+ strerror(errno));
+ sfree(saltname);
+ sfree(parentdirname);
+ return NULL;
+ }
+
+ /*
+ * The salt file doesn't already exist, so try to create
+ * it. Another process may be attempting the same thing
+ * simultaneously, so we must do this carefully: we write
+ * a salt file under a different name, then hard-link it
+ * into place, which guarantees that we won't change the
+ * contents of an existing salt file.
+ */
+ pid = getpid();
+ for (i = 0;; i++) {
+ tmpname = dupprintf("%s/%s.tmp.%d.%d",
+ parentdirname, SALT_FILENAME, pid, i);
+ saltfd = open(tmpname, O_WRONLY | O_EXCL | O_CREAT, 0400);
+ if (saltfd >= 0)
+ break;
+ if (errno != EEXIST) {
+ *logtext = dupprintf("%s: open: %s", tmpname,
+ strerror(errno));
+ sfree(tmpname);
+ sfree(saltname);
+ sfree(parentdirname);
+ return NULL;
+ }
+ sfree(tmpname); /* go round and try again with i+1 */
+ }
+ /*
+ * Invent some random data.
+ */
+ for (i = 0; i < SALT_SIZE; i++) {
+ saltbuf[i] = random_byte();
+ }
+ ret = write(saltfd, saltbuf, SALT_SIZE);
+ /* POSIX atomicity guarantee: because we wrote less than
+ * PIPE_BUF bytes, the write either completed in full or
+ * failed. */
+ assert(SALT_SIZE < PIPE_BUF);
+ assert(ret < 0 || ret == SALT_SIZE);
+ if (ret < 0) {
+ close(saltfd);
+ *logtext = dupprintf("%s: write: %s", tmpname,
+ strerror(errno));
+ sfree(tmpname);
+ sfree(saltname);
+ sfree(parentdirname);
+ return NULL;
+ }
+ if (close(saltfd) < 0) {
+ *logtext = dupprintf("%s: close: %s", tmpname,
+ strerror(errno));
+ sfree(tmpname);
+ sfree(saltname);
+ sfree(parentdirname);
+ return NULL;
+ }
+
+ /*
+ * Now attempt to hard-link our temp file into place. We
+ * tolerate EEXIST as an outcome, because that just means
+ * another PuTTY got their attempt in before we did (and
+ * we only care that there is a valid salt file we can
+ * agree on, no matter who created it).
+ */
+ if (link(tmpname, saltname) < 0 && errno != EEXIST) {
+ *logtext = dupprintf("%s: link: %s", saltname,
+ strerror(errno));
+ sfree(tmpname);
+ sfree(saltname);
+ sfree(parentdirname);
+ return NULL;
+ }
+
+ /*
+ * Whether that succeeded or not, get rid of our temp file.
+ */
+ if (unlink(tmpname) < 0) {
+ *logtext = dupprintf("%s: unlink: %s", tmpname,
+ strerror(errno));
+ sfree(tmpname);
+ sfree(saltname);
+ sfree(parentdirname);
+ return NULL;
+ }
+
+ /*
+ * And now we've arranged for there to be a salt file, so
+ * we can try to open it for reading again and this time
+ * expect it to work.
+ */
+ sfree(tmpname);
+
+ saltfd = open(saltname, O_RDONLY);
+ if (saltfd < 0) {
+ *logtext = dupprintf("%s: open: %s", saltname,
+ strerror(errno));
+ sfree(saltname);
+ sfree(parentdirname);
+ return NULL;
+ }
+ }
+
+ for (i = 0; i < SALT_SIZE; i++) {
+ ret = read(saltfd, saltbuf, SALT_SIZE);
+ if (ret <= 0) {
+ close(saltfd);
+ *logtext = dupprintf("%s: read: %s", saltname,
+ ret == 0 ? "unexpected EOF" :
+ strerror(errno));
+ sfree(saltname);
+ sfree(parentdirname);
+ return NULL;
+ }
+ assert(0 < ret && ret <= SALT_SIZE - i);
+ i += ret;
+ }
+
+ close(saltfd);
+ sfree(saltname);
+
+ /*
+ * Now we've got our salt, hash it with the connection
+ * identifier to produce our actual socket name.
+ */
+ {
+ SHA256_State sha;
+ unsigned len;
+ unsigned char lenbuf[4];
+ unsigned char digest[32];
+ char retbuf[65];
+
+ SHA256_Init(&sha);
+ PUT_32BIT(lenbuf, SALT_SIZE);
+ SHA256_Bytes(&sha, lenbuf, 4);
+ SHA256_Bytes(&sha, saltbuf, SALT_SIZE);
+ len = strlen(pi_name);
+ PUT_32BIT(lenbuf, len);
+ SHA256_Bytes(&sha, lenbuf, 4);
+ SHA256_Bytes(&sha, pi_name, len);
+ SHA256_Final(&sha, digest);
+
+ /*
+ * And make it printable.
+ */
+ for (i = 0; i < 32; i++) {
+ sprintf(retbuf + 2*i, "%02x", digest[i]);
+ /* the last of those will also write the trailing NUL */
+ }
+
+ name = dupstr(retbuf);
+ }
+
+ smemclr(saltbuf, sizeof(saltbuf));
+ }
+
+ dirname = dupprintf("%s/%s", parentdirname, name);
+ sfree(parentdirname);
+ sfree(name);
+
+ return dirname;