Ejemplo n.º 1
0
static int rlogin_closing(Plug plug, const char *error_msg, int error_code,
			  int calling_back)
{
    Rlogin rlogin = (Rlogin) plug;

    /*
     * We don't implement independent EOF in each direction for Telnet
     * connections; as soon as we get word that the remote side has
     * sent us EOF, we wind up the whole connection.
     */

    if (rlogin->s) {
        sk_close(rlogin->s);
        rlogin->s = NULL;
        if (error_msg)
            rlogin->closed_on_socket_error = TRUE;
	notify_remote_exit(rlogin->frontend);
    }
    if (error_msg) {
	/* A socket error has occurred. */
	logevent(rlogin->frontend, error_msg);
	connection_fatal(rlogin->frontend, "%s", error_msg);
    }				       /* Otherwise, the remote side closed the connection normally. */
    return 0;
}
Ejemplo n.º 2
0
static int raw_closing(Plug plug, const char *error_msg, int error_code,
		       int calling_back)
{
    Raw raw = (Raw) plug;

    if (error_msg) {
        /* A socket error has occurred. */
        if (raw->s) {
            sk_close(raw->s);
            raw->s = NULL;
            notify_remote_exit(raw->frontend);
        }
        logevent(raw->frontend, error_msg);
        connection_fatal(raw->frontend, "%s", error_msg);
    } else {
        /* Otherwise, the remote side closed the connection normally. */
        if (!raw->sent_console_eof && from_backend_eof(raw->frontend)) {
            /*
             * The front end wants us to close the outgoing side of the
             * connection as soon as we see EOF from the far end.
             */
            if (!raw->sent_socket_eof) {
                if (raw->s)
                    sk_write_eof(raw->s);
                raw->sent_socket_eof= TRUE;
            }
        }
        raw->sent_console_eof = TRUE;
        raw_check_close(raw);
    }
    return 0;
}
Ejemplo n.º 3
0
static void sk_proxy_close(Socket s) {
	Proxy_Socket ps = (Proxy_Socket) s;

	sk_close(ps->sub_socket);
	sk_addr_free(ps->remote_addr);
	sfree(ps);
}
Ejemplo n.º 4
0
static void adb_free(void *handle)
{
    Adb adb = (Adb) handle;

    if (adb->s)
        sk_close(adb->s);
    sfree(adb);
}
Ejemplo n.º 5
0
static void raw_free(void *handle)
{
    Raw raw = (Raw) handle;

    if (raw->s)
	sk_close(raw->s);
    sfree(raw);
}
Ejemplo n.º 6
0
Archivo: proxy.c Proyecto: Riatre/PuTTY
static void sk_proxy_close (Socket s)
{
    ProxySocket *ps = FROMFIELD(s, ProxySocket, sockvt);

    sk_close(ps->sub_socket);
    sk_addr_free(ps->remote_addr);
    sfree(ps);
}
Ejemplo n.º 7
0
static void sk_proxy_close (Socket *s)
{
    ProxySocket *ps = container_of(s, ProxySocket, sock);

    sk_close(ps->sub_socket);
    sk_addr_free(ps->remote_addr);
    sfree(ps);
}
Ejemplo n.º 8
0
static void rlogin_free(void *handle)
{
    Rlogin rlogin = (Rlogin) handle;

    if (rlogin->s)
	sk_close(rlogin->s);
    sfree(rlogin);
}
Ejemplo n.º 9
0
static void rlogin_free(void *handle)
{
    Rlogin rlogin = (Rlogin) handle;

    if (rlogin->prompt)
        free_prompts(rlogin->prompt);
    if (rlogin->s)
	sk_close(rlogin->s);
    conf_free(rlogin->conf);
    sfree(rlogin);
}
Ejemplo n.º 10
0
void pfd_close(Socket s)
{
    struct PFwdPrivate *pr;

    if (!s)
	return;

    pr = (struct PFwdPrivate *) sk_get_private_ptr(s);

    sfree(pr);

    sk_close(s);
}
Ejemplo n.º 11
0
Archivo: rlogin.c Proyecto: rdebath/sgt
static int rlogin_closing(Plug plug, char *error_msg, int error_code,
			  int calling_back)
{
    if (s) {
        sk_close(s);
        s = NULL;
    }
    if (error_msg) {
	/* A socket error has occurred. */
	connection_fatal(error_msg);
    }				       /* Otherwise, the remote side closed the connection normally. */
    return 0;
}
Ejemplo n.º 12
0
static void raw_check_close(Raw raw)
{
    /*
     * Called after we send EOF on either the socket or the console.
     * Its job is to wind up the session once we have sent EOF on both.
     */
    if (raw->sent_console_eof && raw->sent_socket_eof) {
        if (raw->s) {
            sk_close(raw->s);
            raw->s = NULL;
            notify_remote_exit(raw->frontend);
        }
    }
}
Ejemplo n.º 13
0
static int rlogin_closing(Plug plug, const char *error_msg, int error_code,
			  int calling_back)
{
    Rlogin rlogin = (Rlogin) plug;
    if (rlogin->s) {
        sk_close(rlogin->s);
        rlogin->s = NULL;
    }
    if (error_msg) {
	/* A socket error has occurred. */
	logevent(rlogin->frontend, error_msg);
	connection_fatal(rlogin->frontend, "%s", error_msg);
    }				       /* Otherwise, the remote side closed the connection normally. */
    return 0;
}
Ejemplo n.º 14
0
static int raw_closing(Plug plug, const char *error_msg, int error_code,
		       int calling_back)
{
    Raw raw = (Raw) plug;

    if (raw->s) {
        sk_close(raw->s);
        raw->s = NULL;
	notify_remote_exit(raw->frontend);
    }
    if (error_msg) {
	/* A socket error has occurred. */
	logevent(raw->frontend, error_msg);
	connection_fatal(raw->frontend, "%s", error_msg);
    }				       /* Otherwise, the remote side closed the connection normally. */
    return 0;
}
Ejemplo n.º 15
0
static int
cygterm_closing(Plug plug, const char *error_msg, int error_code, int calling_back)
{
	Local local = (Local)plug;
	cygterm_debug("top");
	if (local->s) {
		sk_close(local->s);
		local->s = NULL;
	}
	/* check for errors from cthelper */
	CloseHandle(local->ctl);
	/* wait for cthelper */
	if (local->pi.hProcess != INVALID_HANDLE_VALUE) {
		if (WAIT_OBJECT_0 == WaitForSingleObject(local->pi.hProcess, 2000)) {
			DWORD status;
			GetExitCodeProcess(local->pi.hProcess, &status);
			switch (status) {
			case CthelperSuccess:
				break;
			case CthelperInvalidUsage:
			case CthelperInvalidPort:
			case CthelperConnectFailed:
				local->exitcode = INT_MAX;
				error_msg = "Internal error";
				break;
			case CthelperPtyforkFailure:
				local->exitcode = INT_MAX;
				error_msg = "Failed to allocate pseudoterminal";
				break;
			case CthelperExecFailure:
				local->exitcode = INT_MAX;
				error_msg = "Failed to execute command";
				break;
			}
		}
	}
	/* this calls cygterm_exitcode() */
	notify_remote_exit(local->frontend);
	if (error_msg) {
		cygterm_debug("error_msg: %s", error_msg);
		connection_fatal(local->frontend, "%s", error_msg);
	}
	return 0;
}
Ejemplo n.º 16
0
static const char *
cygterm_init(void *frontend_handle, void **backend_handle,
             Conf *conf,
             char *unused_host, int unused_port,
             char **realhost, int nodelay, int keepalive)
{
	/* XXX: I'm not sure if it is OK to overload Plug like this.
	 * cygterm_accepting should only be used for the listening socket
	 * (local->a) while the cygterm_closing, cygterm_receive, and cygterm_sent
	 * should be used only for the actual connection (local->s).
	 */
	static const struct plug_function_table fn_table = {
		cygterm_log,
		cygterm_closing,
		cygterm_receive,
		cygterm_sent,
		cygterm_accepting
	};
	Local local;
	const char *command;
	char cmdline[2 * MAX_PATH];
	int cport;
	const char *err;
	int cmdlinelen;

	cygterm_debug("top");

	local = snew(struct cygterm_backend_data);
	local->fn = &fn_table;
	local->a = NULL;
	local->s = NULL;
	local->conf = conf;
	local->editing = 0;
	local->echoing = 0;
	local->exitcode = 0;
	*backend_handle = local;

	local->frontend = frontend_handle;

	/* set up listen socket for communication with child */
	cygterm_debug("setupCygTerm");

	/* let sk use INADDR_LOOPBACK and let WinSock choose a port */
	local->a = sk_newlistener(0, 0, (Plug)local, 1, ADDRTYPE_IPV4);
	if ((err = sk_socket_error(local->a)) != NULL)
		goto fail_free;

	/* now, get the port that WinSock chose */
	/* XXX: Is there another function in PuTTY to do this? */
	cygterm_debug("getting port");
	cport = sk_getport(local->a);
	if (cport == -1) {
		err = "Failed to get port number for cthelper";
		goto fail_close;
	}

	if (strchr(conf_get_str(local->conf, CONF_termtype), ' ')) {
		err = "term type contains spaces";
		goto fail_close;
	}

	/*  Build cthelper command line */
	if(conf_get_int(conf, CONF_cygterm64)) {
		cmdlinelen = sprintf(cmdline, CTHELPER64" %u %s ", cport, conf_get_str(local->conf, CONF_termtype));
	}
	else {
		cmdlinelen = sprintf(cmdline, CTHELPER" %u %s ", cport, conf_get_str(local->conf, CONF_termtype));
	}
	cmdlinelen += makeAttributes(cmdline + cmdlinelen, conf);

	command = conf_get_str(conf, CONF_cygcmd);
	cygterm_debug("command is :%s:", command);
	/*  A command of  "."  or  "-"  tells us to pass no command arguments to
	 *  cthelper which will then run the user's shell under Cygwin.  */
	if ((command[0]=='-'||command[0]=='.') && command[1]=='\0')
		;
	else if (cmdlinelen + strlen(command) + 2 > sizeof cmdline) {
		err = "command is too long";
		goto fail_close;
	}
	else {
		cmdlinelen += sprintf(cmdline + cmdlinelen, " %s", command);
	}

	/* Add the Cygwin /bin path to the PATH. */
	if (conf_get_int(conf, CONF_cygautopath)) {
		char *cygwinBinPath = getCygwinBin(conf_get_int(conf, CONF_cygterm64));
		if (!cygwinBinPath) {
			/* we'll try anyway */
			cygterm_debug("cygwin bin directory not found");
		}
		else {
			cygterm_debug("found cygwin directory: %s", cygwinBinPath);
			appendPath(cygwinBinPath);
			sfree(cygwinBinPath);
		}
	}

	cygterm_debug("starting cthelper: %s", cmdline);
	if ((err = spawnChild(cmdline, &local->pi, &local->ctl)))
		goto fail_close;

	/*  This should be set to the local hostname, Apparently, realhost is used
	 *  only to set the window title.
	 */
	strcpy(*realhost = smalloc(sizeof CYGTERM_NAME), CYGTERM_NAME);
	cygterm_debug("OK");
	return 0;

fail_close:
	sk_close(local->a);
fail_free:
	sfree(local);
	return err;
}
Ejemplo n.º 17
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 *name, *mutexname, *pipename;
    HANDLE mutex;
    Socket retsock;
    PSECURITY_DESCRIPTOR psd;
    PACL acl;

    /*
     * Transform the platform-independent version of the connection
     * identifier into the obfuscated version we'll use for our
     * Windows named pipe and mutex. A side effect of doing this is
     * that it also eliminates any characters illegal in Windows pipe
     * names.
     */
    name = obfuscate_name(pi_name);
    if (!name) {
        *logtext = dupprintf("Unable to call CryptProtectMemory: %s",
                             win_strerror(GetLastError()));
        return SHARE_NONE;
    }

    /*
     * Make a mutex name out of the connection identifier, and lock it
     * while we decide whether to be upstream or downstream.
     */
    {
        SECURITY_ATTRIBUTES sa;

        mutexname = make_name(CONNSHARE_MUTEX_PREFIX, name);
        if (!make_private_security_descriptor(MUTEX_ALL_ACCESS,
                                              &psd, &acl, logtext)) {
            sfree(mutexname);
            return SHARE_NONE;
        }

        memset(&sa, 0, sizeof(sa));
        sa.nLength = sizeof(sa);
        sa.lpSecurityDescriptor = psd;
        sa.bInheritHandle = FALSE;

        mutex = CreateMutex(&sa, FALSE, mutexname);

        if (!mutex) {
            *logtext = dupprintf("CreateMutex(\"%s\") failed: %s",
                                 mutexname, win_strerror(GetLastError()));
            sfree(mutexname);
            LocalFree(psd);
            LocalFree(acl);
            return SHARE_NONE;
        }

        sfree(mutexname);
        LocalFree(psd);
        LocalFree(acl);

        WaitForSingleObject(mutex, INFINITE);
    }

    pipename = make_name(CONNSHARE_PIPE_PREFIX, name);

    *logtext = NULL;

    if (can_downstream) {
        retsock = new_named_pipe_client(pipename, downplug);
        if (sk_socket_error(retsock) == NULL) {
            sfree(*logtext);
            *logtext = pipename;
            *sock = retsock;
            sfree(name);
            ReleaseMutex(mutex);
            CloseHandle(mutex);
            return SHARE_DOWNSTREAM;
        }
        sfree(*ds_err);
        *ds_err = dupprintf("%s: %s", pipename, sk_socket_error(retsock));
        sk_close(retsock);
    }

    if (can_upstream) {
        retsock = new_named_pipe_listener(pipename, upplug);
        if (sk_socket_error(retsock) == NULL) {
            sfree(*logtext);
            *logtext = pipename;
            *sock = retsock;
            sfree(name);
            ReleaseMutex(mutex);
            CloseHandle(mutex);
            return SHARE_UPSTREAM;
        }
        sfree(*us_err);
        *us_err = dupprintf("%s: %s", pipename, sk_socket_error(retsock));
        sk_close(retsock);
    }

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

    sfree(pipename);
    sfree(name);
    ReleaseMutex(mutex);
    CloseHandle(mutex);
    return SHARE_NONE;
}
Ejemplo n.º 18
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;
}
Ejemplo n.º 19
0
struct X11Display *x11_setup_display(char *display, int authtype, Conf *conf)
{
    struct X11Display *disp = snew(struct X11Display);
    char *localcopy;
    int i;

    if (!display || !*display) {
	localcopy = platform_get_x_display();
	if (!localcopy || !*localcopy) {
	    sfree(localcopy);
	    localcopy = dupstr(":0");  /* plausible default for any platform */
	}
    } else
	localcopy = dupstr(display);

    /*
     * Parse the display name.
     *
     * We expect this to have one of the following forms:
     * 
     *  - the standard X format which looks like
     *    [ [ protocol '/' ] host ] ':' displaynumber [ '.' screennumber ]
     *    (X11 also permits a double colon to indicate DECnet, but
     *    that's not our problem, thankfully!)
     *
     * 	- only seen in the wild on MacOS (so far): a pathname to a
     * 	  Unix-domain socket, which will typically and confusingly
     * 	  end in ":0", and which I'm currently distinguishing from
     * 	  the standard scheme by noting that it starts with '/'.
     */
    if (localcopy[0] == '/') {
	disp->unixsocketpath = localcopy;
	disp->unixdomain = TRUE;
	disp->hostname = NULL;
	disp->displaynum = -1;
	disp->screennum = 0;
	disp->addr = NULL;
    } else {
	char *colon, *dot, *slash;
	char *protocol, *hostname;

	colon = strrchr(localcopy, ':');
	if (!colon) {
	    sfree(disp);
	    sfree(localcopy);
	    return NULL;	       /* FIXME: report a specific error? */
	}

	*colon++ = '\0';
	dot = strchr(colon, '.');
	if (dot)
	    *dot++ = '\0';

	disp->displaynum = atoi(colon);
	if (dot)
	    disp->screennum = atoi(dot);
	else
	    disp->screennum = 0;

	protocol = NULL;
	hostname = localcopy;
	if (colon > localcopy) {
	    slash = strchr(localcopy, '/');
	    if (slash) {
		*slash++ = '\0';
		protocol = localcopy;
		hostname = slash;
	    }
	}

	disp->hostname = *hostname ? dupstr(hostname) : NULL;

	if (protocol)
	    disp->unixdomain = (!strcmp(protocol, "local") ||
				!strcmp(protocol, "unix"));
	else if (!*hostname || !strcmp(hostname, "unix"))
	    disp->unixdomain = platform_uses_x11_unix_by_default;
	else
	    disp->unixdomain = FALSE;

	if (!disp->hostname && !disp->unixdomain)
	    disp->hostname = dupstr("localhost");

	disp->unixsocketpath = NULL;
	disp->addr = NULL;

	sfree(localcopy);
    }

    /*
     * Look up the display hostname, if we need to.
     */
    if (!disp->unixdomain) {
	const char *err;

	disp->port = 6000 + disp->displaynum;
	disp->addr = name_lookup(disp->hostname, disp->port,
				 &disp->realhost, conf, ADDRTYPE_UNSPEC);
    
	if ((err = sk_addr_error(disp->addr)) != NULL) {
	    sk_addr_free(disp->addr);
	    sfree(disp->hostname);
	    sfree(disp->unixsocketpath);
	    sfree(disp);
	    return NULL;	       /* FIXME: report an error */
	}
    }

    /*
     * Try upgrading an IP-style localhost display to a Unix-socket
     * display (as the standard X connection libraries do).
     */
    if (!disp->unixdomain && sk_address_is_local(disp->addr)) {
	SockAddr ux = platform_get_x11_unix_address(NULL, disp->displaynum);
	const char *err = sk_addr_error(ux);
	if (!err) {
	    /* Create trial connection to see if there is a useful Unix-domain
	     * socket */
	    const struct plug_function_table *dummy = &dummy_plug;
	    Socket s = putty_sk_new(sk_addr_dup(ux), 0, 0, 0, 0, 0, (Plug)&dummy
	    #ifdef MPEXT
		,
	    0, 0
	    #endif
	    );
	    err = sk_socket_error(s);
	    sk_close(s);
	}
	if (err) {
	    sk_addr_free(ux);
	} else {
	    sk_addr_free(disp->addr);
	    disp->unixdomain = TRUE;
	    disp->addr = ux;
	    /* Fill in the rest in a moment */
	}
    }

    if (disp->unixdomain) {
	if (!disp->addr)
	    disp->addr = platform_get_x11_unix_address(disp->unixsocketpath,
						       disp->displaynum);
	if (disp->unixsocketpath)
	    disp->realhost = dupstr(disp->unixsocketpath);
	else
	    disp->realhost = dupprintf("unix:%d", disp->displaynum);
	disp->port = 0;
    }

    /*
     * Invent the remote authorisation details.
     */
    if (authtype == X11_MIT) {
	disp->remoteauthproto = X11_MIT;

	/* MIT-MAGIC-COOKIE-1. Cookie size is 128 bits (16 bytes). */
	disp->remoteauthdata = snewn(16, unsigned char);
	for (i = 0; i < 16; i++)
	    disp->remoteauthdata[i] = random_byte();
	disp->remoteauthdatalen = 16;

	disp->xdmseen = NULL;
    } else {
Ejemplo n.º 20
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;
}