+ pty_name[FILENAME_MAX-1] = '\0';
+ strncpy(pty_name, ptsname(pty_master_fd), FILENAME_MAX-1);
+#endif
+}
+
+/*
+ * Pre-initialisation. This is here to get around the fact that GTK
+ * doesn't like being run in setuid/setgid programs (probably
+ * sensibly). So before we initialise GTK - and therefore before we
+ * even process the command line - we check to see if we're running
+ * set[ug]id. If so, we open our pty master _now_, chown it as
+ * necessary, and drop privileges. We can always close it again
+ * later. If we're potentially going to be doing utmp as well, we
+ * also fork off a utmp helper process and communicate with it by
+ * means of a pipe; the utmp helper will keep privileges in order
+ * to clean up utmp when we exit (i.e. when its end of our pipe
+ * closes).
+ */
+void pty_pre_init(void)
+{
+ pid_t pid;
+ int pipefd[2];
+
+ /* set the child signal handler straight away; it needs to be set
+ * before we ever fork. */
+ putty_signal(SIGCHLD, sigchld_handler);
+ pty_master_fd = -1;
+
+ if (geteuid() != getuid() || getegid() != getgid()) {
+ pty_open_master();
+ }
+
+#ifndef OMIT_UTMP
+ /*
+ * Fork off the utmp helper.
+ */
+ if (pipe(pipefd) < 0) {
+ perror("pterm: pipe");
+ exit(1);
+ }
+ pid = fork();
+ if (pid < 0) {
+ perror("pterm: fork");
+ exit(1);
+ } else if (pid == 0) {
+ char display[128], buffer[128];
+ int dlen, ret;
+
+ close(pipefd[1]);
+ /*
+ * Now sit here until we receive a display name from the
+ * other end of the pipe, and then stamp utmp. Unstamp utmp
+ * again, and exit, when the pipe closes.
+ */
+
+ dlen = 0;
+ while (1) {
+
+ ret = read(pipefd[0], buffer, lenof(buffer));
+ if (ret <= 0) {
+ cleanup_utmp();
+ _exit(0);
+ } else if (!pty_stamped_utmp) {
+ if (dlen < lenof(display))
+ memcpy(display+dlen, buffer,
+ min(ret, lenof(display)-dlen));
+ if (buffer[ret-1] == '\0') {
+ /*
+ * Now we have a display name. NUL-terminate
+ * it, and stamp utmp.
+ */
+ display[lenof(display)-1] = '\0';
+ /*
+ * Trap as many fatal signals as we can in the
+ * hope of having the best possible chance to
+ * clean up utmp before termination. We are
+ * unfortunately unprotected against SIGKILL,
+ * but that's life.
+ */
+ putty_signal(SIGHUP, fatal_sig_handler);
+ putty_signal(SIGINT, fatal_sig_handler);
+ putty_signal(SIGQUIT, fatal_sig_handler);
+ putty_signal(SIGILL, fatal_sig_handler);
+ putty_signal(SIGABRT, fatal_sig_handler);
+ putty_signal(SIGFPE, fatal_sig_handler);
+ putty_signal(SIGPIPE, fatal_sig_handler);
+ putty_signal(SIGALRM, fatal_sig_handler);
+ putty_signal(SIGTERM, fatal_sig_handler);
+ putty_signal(SIGSEGV, fatal_sig_handler);
+ putty_signal(SIGUSR1, fatal_sig_handler);
+ putty_signal(SIGUSR2, fatal_sig_handler);
+#ifdef SIGBUS
+ putty_signal(SIGBUS, fatal_sig_handler);
+#endif
+#ifdef SIGPOLL
+ putty_signal(SIGPOLL, fatal_sig_handler);
+#endif
+#ifdef SIGPROF
+ putty_signal(SIGPROF, fatal_sig_handler);
+#endif
+#ifdef SIGSYS
+ putty_signal(SIGSYS, fatal_sig_handler);
+#endif
+#ifdef SIGTRAP
+ putty_signal(SIGTRAP, fatal_sig_handler);
+#endif
+#ifdef SIGVTALRM
+ putty_signal(SIGVTALRM, fatal_sig_handler);
+#endif
+#ifdef SIGXCPU
+ putty_signal(SIGXCPU, fatal_sig_handler);
+#endif
+#ifdef SIGXFSZ
+ putty_signal(SIGXFSZ, fatal_sig_handler);
+#endif
+#ifdef SIGIO
+ putty_signal(SIGIO, fatal_sig_handler);
+#endif
+ setup_utmp(pty_name, display);
+ }
+ }
+ }
+ } else {
+ close(pipefd[0]);
+ pty_utmp_helper_pid = pid;
+ pty_utmp_helper_pipe = pipefd[1];
+ }
+#endif
+
+ /* Drop privs. */
+ {
+ int gid = getgid(), uid = getuid();
+#ifndef HAVE_NO_SETRESUID
+ int setresgid(gid_t, gid_t, gid_t);
+ int setresuid(uid_t, uid_t, uid_t);
+ setresgid(gid, gid, gid);
+ setresuid(uid, uid, uid);
+#else
+ setgid(getgid());
+ setuid(getuid());