Esempio n. 1
0
int platform_ssh_share(const char *pi_name, Conf *conf,
                       Plug downplug, Plug upplug, Socket *sock,
                       char **logtext, char **ds_err, char **us_err,
                       int can_upstream, int can_downstream)
{
    char *dirname, *lockname, *sockname, *err;
    int lockfd;
    Socket retsock;

    /*
     * Sort out what we're going to call the directory in which we
     * keep the socket. This has the side effect of potentially
     * creating its top-level containing dir and/or the salt file
     * within that, if they don't already exist.
     */
    dirname = make_dirname(pi_name, logtext);
    if (!dirname) {
        return SHARE_NONE;
    }

    /*
     * Now make sure the subdirectory exists.
     */
    if ((err = make_dir_and_check_ours(dirname)) != NULL) {
        *logtext = err;
        sfree(dirname);
        return SHARE_NONE;
    }

    /*
     * Acquire a lock on a file in that directory.
     */
    lockname = dupcat(dirname, "/lock", (char *)NULL);
    lockfd = open(lockname, O_CREAT | O_RDWR | O_TRUNC, 0600);
    if (lockfd < 0) {
        *logtext = dupprintf("%s: open: %s", lockname, strerror(errno));
        sfree(dirname);
        sfree(lockname);
        return SHARE_NONE;
    }
    if (flock(lockfd, LOCK_EX) < 0) {
        *logtext = dupprintf("%s: flock(LOCK_EX): %s",
                             lockname, strerror(errno));
        sfree(dirname);
        sfree(lockname);
        close(lockfd);
        return SHARE_NONE;
    }

    sockname = dupprintf("%s/socket", dirname);

    *logtext = NULL;

    if (can_downstream) {
        retsock = new_connection(unix_sock_addr(sockname),
                                 "", 0, 0, 1, 0, 0, downplug, conf);
        if (sk_socket_error(retsock) == NULL) {
            sfree(*logtext);
            *logtext = sockname;
            *sock = retsock;
            sfree(dirname);
            sfree(lockname);
            close(lockfd);
            return SHARE_DOWNSTREAM;
        }
        sfree(*ds_err);
        *ds_err = dupprintf("%s: %s", sockname, sk_socket_error(retsock));
        sk_close(retsock);
    }

    if (can_upstream) {
        retsock = new_unix_listener(unix_sock_addr(sockname), upplug);
        if (sk_socket_error(retsock) == NULL) {
            sfree(*logtext);
            *logtext = sockname;
            *sock = retsock;
            sfree(dirname);
            sfree(lockname);
            close(lockfd);
            return SHARE_UPSTREAM;
        }
        sfree(*us_err);
        *us_err = dupprintf("%s: %s", sockname, sk_socket_error(retsock));
        sk_close(retsock);
    }

    /* One of the above clauses ought to have happened. */
    assert(*logtext || *ds_err || *us_err);

    sfree(dirname);
    sfree(lockname);
    sfree(sockname);
    close(lockfd);
    return SHARE_NONE;
}
Esempio n. 2
0
int platform_make_x11_server(Plug *plug, const char *progname, int mindisp,
                             const char *screen_number_suffix,
                             ptrlen authproto, ptrlen authdata,
                             Socket **sockets, Conf *conf)
{
    char *tmpdir;
    char *authfilename = NULL;
    strbuf *authfiledata = NULL;
    char *unix_path = NULL;

    SockAddr *a_tcp = NULL, *a_unix = NULL;

    int authfd;
    FILE *authfp;

    int displayno;

    authfiledata = strbuf_new_nm();

    int nsockets = 0;

    /*
     * Look for a free TCP port to run our server on.
     */
    for (displayno = mindisp;; displayno++) {
        const char *err;
        int tcp_port = displayno + 6000;
        int addrtype = ADDRTYPE_IPV4;

        sockets[nsockets] = new_listener(
            NULL, tcp_port, plug, false, conf, addrtype);

        err = sk_socket_error(sockets[nsockets]);
        if (!err) {
            char *hostname = get_hostname();
            if (hostname) {
                char *canonicalname = NULL;
                a_tcp = name_lookup(hostname, tcp_port, &canonicalname,
                                    conf, addrtype, NULL, "");
                sfree(canonicalname);
            }
            sfree(hostname);
            nsockets++;
            break;                     /* success! */
        } else {
            sk_close(sockets[nsockets]);
        }

        if (!strcmp(err, strerror(EADDRINUSE))) /* yuck! */
            goto out;
    }

    if (a_tcp) {
        x11_format_auth_for_authfile(
            BinarySink_UPCAST(authfiledata),
            a_tcp, displayno, authproto, authdata);
    }

    /*
     * Try to establish the Unix-domain analogue. That may or may not
     * work - file permissions in /tmp may prevent it, for example -
     * but it's worth a try, and we don't consider it a fatal error if
     * it doesn't work.
     */
    unix_path = dupprintf("/tmp/.X11-unix/X%d", displayno);
    a_unix = unix_sock_addr(unix_path);

    sockets[nsockets] = new_unix_listener(a_unix, plug);
    if (!sk_socket_error(sockets[nsockets])) {
        x11_format_auth_for_authfile(
            BinarySink_UPCAST(authfiledata),
            a_unix, displayno, authproto, authdata);
        nsockets++;
    } else {
        sk_close(sockets[nsockets]);
        sfree(unix_path);
        unix_path = NULL;
    }

    /*
     * Decide where the authority data will be written.
     */

    tmpdir = getenv("TMPDIR");
    if (!tmpdir || !*tmpdir)
        tmpdir = "/tmp";

    authfilename = dupcat(tmpdir, "/", progname, "-Xauthority-XXXXXX", NULL);

    {
        int oldumask = umask(077);
        authfd = mkstemp(authfilename);
        umask(oldumask);
    }
    if (authfd < 0) {
        while (nsockets-- > 0)
            sk_close(sockets[nsockets]);
        goto out;
    }

    /*
     * Spawn a subprocess which will try to reliably delete our
     * auth file when we terminate, in case we die unexpectedly.
     */
    {
        int cleanup_pipe[2];
        pid_t pid;

        /* Don't worry if pipe or fork fails; it's not _that_ critical. */
        if (!pipe(cleanup_pipe)) {
            if ((pid = fork()) == 0) {
                int buf[1024];
                /*
                 * Our parent process holds the writing end of
                 * this pipe, and writes nothing to it. Hence,
                 * we expect read() to return EOF as soon as
                 * that process terminates.
                 */

                close(0);
                close(1);
                close(2);

                setpgid(0, 0);
                close(cleanup_pipe[1]);
                close(authfd);
                while (read(cleanup_pipe[0], buf, sizeof(buf)) > 0);
                unlink(authfilename);
                if (unix_path)
                    unlink(unix_path);
                _exit(0);
            } else if (pid < 0) {
                close(cleanup_pipe[0]);
                close(cleanup_pipe[1]);
            } else {
                close(cleanup_pipe[0]);
                cloexec(cleanup_pipe[1]);
            }
        }
    }

    authfp = fdopen(authfd, "wb");
    fwrite(authfiledata->u, 1, authfiledata->len, authfp);
    fclose(authfp);

    {
        char *display = dupprintf(":%d%s", displayno, screen_number_suffix);
        conf_set_str_str(conf, CONF_environmt, "DISPLAY", display);
        sfree(display);
    }
    conf_set_str_str(conf, CONF_environmt, "XAUTHORITY", authfilename);

    /*
     * FIXME: return at least the DISPLAY and XAUTHORITY env settings,
     * and perhaps also the display number
     */

  out:
    if (a_tcp)
        sk_addr_free(a_tcp);
    /* a_unix doesn't need freeing, because new_unix_listener took it over */
    sfree(authfilename);
    strbuf_free(authfiledata);
    sfree(unix_path);
    return nsockets;
}