예제 #1
0
static void tlsp_service(VSTREAM *plaintext_stream,
                         char *service,
                         char **argv)
{
    TLSP_STATE *state;
    int     plaintext_fd = vstream_fileno(plaintext_stream);

    /*
     * Sanity check. This service takes no command-line arguments.
     */
    if (argv[0])
        msg_fatal("unexpected command-line argument: %s", argv[0]);

    /*
     * This program handles multiple connections, so it must not block. We
     * use event-driven code for all operations that introduce latency.
     * Except that attribute lists are sent/received synchronously, once the
     * socket is found to be ready for transmission.
     */
    non_blocking(plaintext_fd, NON_BLOCKING);
    vstream_control(plaintext_stream,
                    CA_VSTREAM_CTL_PATH("plaintext"),
                    CA_VSTREAM_CTL_TIMEOUT(5),
                    CA_VSTREAM_CTL_END);

    /*
     * Receive postscreen's remote SMTP client address/port and socket.
     */
    state = tlsp_state_create(service, plaintext_stream);
    event_enable_read(plaintext_fd, tlsp_get_request_event, (void *) state);
    event_request_timer(tlsp_get_request_event, (void *) state,
                        TLSP_INIT_TIMEOUT);
}
예제 #2
0
int     recv_pass_attr(int fd, HTABLE **attr, int timeout, ssize_t bufsize)
{
    VSTREAM *fp;
    int     stream_err;

    /*
     * Set up a temporary VSTREAM to receive the attributes.
     * 
     * XXX We use one-character reads to simplify the implementation.
     */
    fp = vstream_fdopen(fd, O_RDWR);
    vstream_control(fp,
		    CA_VSTREAM_CTL_BUFSIZE(bufsize),
		    CA_VSTREAM_CTL_TIMEOUT(timeout),
		    CA_VSTREAM_CTL_START_DEADLINE,
		    CA_VSTREAM_CTL_END);
    stream_err = (attr_scan(fp, ATTR_FLAG_NONE,
			    ATTR_TYPE_HASH, *attr = htable_create(1),
			    ATTR_TYPE_END) < 0
		  || vstream_feof(fp) || vstream_ferror(fp));
    vstream_fdclose(fp);

    /*
     * Error reporting and recovery.
     */
    if (stream_err) {
	htable_free(*attr, myfree);
	*attr = 0;
	return (-1);
    } else {
	if ((*attr)->used == 0) {
	    htable_free(*attr, myfree);
	    *attr = 0;
	}
	return (0);
    }
}
예제 #3
0
static int xsasl_dovecot_server_connect(XSASL_DOVECOT_SERVER_IMPL *xp)
{
    const char *myname = "xsasl_dovecot_server_connect";
    VSTRING *line_str;
    VSTREAM *sasl_stream;
    char   *line, *cmd, *mech_name;
    unsigned int major_version, minor_version;
    int     fd, success, have_mech_line;
    int     sec_props;
    const char *path;

    if (msg_verbose)
	msg_info("%s: Connecting", myname);

    /*
     * Not documented, but necessary for testing.
     */
    path = xp->socket_path;
    if (strncmp(path, "inet:", 5) == 0) {
	fd = inet_connect(path + 5, BLOCKING, AUTH_TIMEOUT);
    } else {
	if (strncmp(path, "unix:", 5) == 0)
	    path += 5;
	fd = unix_connect(path, BLOCKING, AUTH_TIMEOUT);
    }
    if (fd < 0) {
	msg_warn("SASL: Connect to %s failed: %m", xp->socket_path);
	return (-1);
    }
    sasl_stream = vstream_fdopen(fd, O_RDWR);
    vstream_control(sasl_stream,
		    CA_VSTREAM_CTL_PATH(xp->socket_path),
		    CA_VSTREAM_CTL_TIMEOUT(AUTH_TIMEOUT),
		    CA_VSTREAM_CTL_END);

    /* XXX Encapsulate for logging. */
    vstream_fprintf(sasl_stream,
		    "VERSION\t%u\t%u\n"
		    "CPID\t%u\n",
		    AUTH_PROTOCOL_MAJOR_VERSION,
		    AUTH_PROTOCOL_MINOR_VERSION,
		    (unsigned int) getpid());
    if (vstream_fflush(sasl_stream) == VSTREAM_EOF) {
	msg_warn("SASL: Couldn't send handshake: %m");
	return (-1);
    }
    success = 0;
    have_mech_line = 0;
    line_str = vstring_alloc(256);
    /* XXX Encapsulate for logging. */
    while (vstring_get_nonl(line_str, sasl_stream) != VSTREAM_EOF) {
	line = vstring_str(line_str);

	if (msg_verbose)
	    msg_info("%s: auth reply: %s", myname, line);

	cmd = line;
	line = split_at(line, '\t');

	if (strcmp(cmd, "VERSION") == 0) {
	    if (sscanf(line, "%u\t%u", &major_version, &minor_version) != 2) {
		msg_warn("SASL: Protocol version error");
		break;
	    }
	    if (major_version != AUTH_PROTOCOL_MAJOR_VERSION) {
		/* Major version is different from ours. */
		msg_warn("SASL: Protocol version mismatch (%d vs. %d)",
			 major_version, AUTH_PROTOCOL_MAJOR_VERSION);
		break;
	    }
	} else if (strcmp(cmd, "MECH") == 0 && line != NULL) {
	    mech_name = line;
	    have_mech_line = 1;
	    line = split_at(line, '\t');
	    if (line != 0) {
		sec_props =
		    name_mask_delim_opt(myname,
					xsasl_dovecot_serv_sec_props,
					line, "\t",
				     NAME_MASK_ANY_CASE | NAME_MASK_IGNORE);
		if ((sec_props & SEC_PROPS_PRIVATE) != 0)
		    continue;
	    } else
		sec_props = 0;
	    xsasl_dovecot_server_mech_append(&xp->mechanism_list, mech_name,
					     sec_props);
	} else if (strcmp(cmd, "SPID") == 0) {

	    /*
	     * Unfortunately the auth protocol handshake wasn't designed well
	     * to differentiate between auth-client/userdb/master.
	     * auth-userdb and auth-master send VERSION + SPID lines only and
	     * nothing afterwards, while auth-client sends VERSION + MECH +
	     * SPID + CUID + more. The simplest way that we can determine if
	     * we've connected to the correct socket is to see if MECH line
	     * exists or not (alternatively we'd have to have a small timeout
	     * after SPID to see if CUID is sent or not).
	     */
	    if (!have_mech_line) {
		msg_warn("SASL: Connected to wrong auth socket (auth-master instead of auth-client)");
		break;
	    }
	} else if (strcmp(cmd, "DONE") == 0) {
	    /* Handshake finished. */
	    success = 1;
	    break;
	} else {
	    /* ignore any unknown commands */
	}
    }
    vstring_free(line_str);

    if (!success) {
	/* handshake failed */
	(void) vstream_fclose(sasl_stream);
	return (-1);
    }
    xp->sasl_stream = sasl_stream;
    return (0);
}