Beispiel #1
0
/* Select handler which is set for the socket descriptor when connect() has
 * indicated (via errno) that it is in progress. On completion this handler gets
 * called. */
static void
connected(struct socket *socket)
{
	int err = 0;
	struct connection_state state = connection_state(0);
	socklen_t len = sizeof(err);

	assertm(socket->connect_info != NULL, "Lost connect_info!");
	if_assert_failed return;

	if (getsockopt(socket->fd, SOL_SOCKET, SO_ERROR, (void *) &err, &len) == 0) {
		/* Why does EMX return so large values? */
		if (err >= 10000) err -= 10000;
		if (err != 0)
			state = connection_state_for_errno(err);
		else
			state = connection_state(0);
	} else {
		/* getsockopt() failed */
		if (errno != 0)
			state = connection_state_for_errno(errno);
		else
			state = connection_state(S_STATE);
	}

	if (!is_in_state(state, 0)) {
		/* There are maybe still some more candidates. */
		connect_socket(socket, state);
		return;
	}

	complete_connect_socket(socket, NULL, NULL);
}
Beispiel #2
0
static void
ssl_want_read(struct socket *socket)
{
	if (socket->no_tls)
		ssl_set_no_tls(socket);

	switch (ssl_do_connect(socket)) {
		case SSL_ERROR_NONE:
#ifdef CONFIG_GNUTLS
			if (get_opt_bool((const unsigned char *)"connection.ssl.cert_verify", NULL)
			    && verify_certificates(socket)) {
				socket->ops->retry(socket, connection_state(S_SSL_ERROR));
				return;
			}
#endif

			/* Report successful SSL connection setup. */
			complete_connect_socket(socket, NULL, NULL);
			break;

		case SSL_ERROR_WANT_READ:
		case SSL_ERROR_WANT_READ2:
			break;

		default:
			socket->no_tls = !socket->no_tls;
			socket->ops->retry(socket, connection_state(S_SSL_ERROR));
	}
}
Beispiel #3
0
static void
fsp_directory(FSP_SESSION *ses, struct uri *uri)
{
	struct string buf;
	FSP_DIR *dir;
	unsigned char *data = get_uri_string(uri, URI_DATA);
	unsigned char dircolor[8] = "";

	if (!data)
		fsp_error(connection_state(S_OUT_OF_MEM));
	decode_uri(data);
	if (!is_in_state(init_directory_listing(&buf, uri), S_OK))
		fsp_error(connection_state(S_OUT_OF_MEM));

	dir = fsp_opendir(ses, data);
	if (!dir) fsp_error(connection_state_for_errno(errno));

	fprintf(stderr, "text/html");
	fclose(stderr);

	puts(buf.source);

	if (get_opt_bool("document.browse.links.color_dirs", NULL)) {
		color_to_string(get_opt_color("document.colors.dirs", NULL),
				dircolor);
	}

	sort_and_display_entries(dir, dircolor);
	fsp_closedir(dir);
	puts("</pre><hr/></body></html>");
	fsp_close_session(ses);
	exit(0);
}
Beispiel #4
0
static void
smb_got_data(struct socket *socket, struct read_buffer *rb)
{
	int len = rb->length;
	struct connection *conn = socket->conn;

	if (len < 0) {
		abort_connection(conn, connection_state_for_errno(errno));
		return;
	}

	if (!len) {
		abort_connection(conn, connection_state(S_OK));
		return;
	}

	socket->state = SOCKET_END_ONCLOSE;
	conn->received += len;
	if (add_fragment(conn->cached, conn->from, rb->data, len) == 1)
		conn->tries = 0;
	conn->from += len;
	kill_buffer_data(rb, len);

	read_from_socket(socket, rb, connection_state(S_TRANS), smb_got_data);
}
Beispiel #5
0
static struct uri *
proxy_uri(struct uri *uri, unsigned char *proxy,
          struct connection_state *error_state)
{
    struct string string;

    if (init_string(&string)
            && string_concat(&string, "proxy://", proxy, "/",
                             (unsigned char *) NULL)
            && add_uri_to_string(&string, uri, URI_BASE)) {
        /* There is no need to use URI_BASE when calling get_uri()
         * because URI_BASE should not add any fragments in the first
         * place. */
        uri = get_uri(string.source, 0);
        /* XXX: Assume the problem is due to @proxy having bad format.
         * This is a lot faster easier than checking the format. */
        if (!uri)
            *error_state = connection_state(S_PROXY_ERROR);
    } else {
        uri = NULL;
        *error_state = connection_state(S_OUT_OF_MEM);
    }

    done_string(&string);
    return uri;
}
Beispiel #6
0
/* DNS callback. */
static void
dns_found(struct socket *socket, struct sockaddr_storage *addr, int addrlen)
{
	struct connect_info *connect_info = socket->connect_info;
	int size;

	if (!addr) {
		socket->ops->done(socket, connection_state(S_NO_DNS));
		return;
	}

	assert(connect_info);

	size = sizeof(*addr) * addrlen;

	connect_info->addr = mem_alloc(size);
	if (!connect_info->addr) {
		socket->ops->done(socket, connection_state(S_OUT_OF_MEM));
		return;
	}

	memcpy(connect_info->addr, addr, size);
	connect_info->addrno = addrlen;

	/* XXX: Passing non-result state here is bad but a lack of alternatives
	 * makes it so. Well adding get_state() socket operation could maybe fix
	 * it but the returned state would most likely be a non-result one at
	 * this point in the connection lifecycle. This will, however, only be a
	 * problem if connect_socket() fails without doing any system calls
	 * which is only the case when forcing the IP family. So it is better to
	 * handle it in connect_socket(). */
	connect_socket(socket, connection_state(S_CONN));
}
Beispiel #7
0
/* Returns a connection state. S_OK if all is well. */
static inline struct connection_state
list_directory(struct connection *conn, unsigned char *dirpath,
	       struct string *page)
{
	int show_hidden_files = get_opt_bool((const unsigned char *)"protocol.file.show_hidden_files",
	                                     NULL);
	struct directory_entry *entries;
	struct connection_state state;

	errno = 0;
	entries = get_directory_entries(dirpath, show_hidden_files);
	if (!entries) {
		if (errno) return connection_state_for_errno(errno);
		return connection_state(S_OUT_OF_MEM);
	}

	state = init_directory_listing(page, conn->uri);
	if (!is_in_state(state, S_OK))
		return connection_state(S_OUT_OF_MEM);

	add_dir_entries(entries, dirpath, page);

	if (!add_to_string(page, (const unsigned char *)"</pre>\n<hr/>\n</body>\n</html>\n")) {
		done_string(page);
		return connection_state(S_OUT_OF_MEM);
	}

	return connection_state(S_OK);
}
Beispiel #8
0
/** @return -2 if no data was read but the caller should retry;
 * -1 if an error occurred and *@a error was set; 0 at end of data;
 * a positive number if that many bytes were read.
 *
 * @relates http_post */
static int
read_http_post_fd(struct http_post *http_post,
		  unsigned char buffer[], int max,
		  struct connection_state *error)
{
	const struct http_post_file *const file
		= &http_post->files[http_post->file_index];
	int ret;

	/* safe_read() would set errno = EBADF anyway, but check this
	 * explicitly to make any such bugs easier to detect.  */
	assert(http_post->post_fd >= 0);
	if_assert_failed { *error = connection_state(S_INTERNAL); return -1; }

	ret = safe_read(http_post->post_fd, buffer, max);
	if (ret <= 0) {
		const int errno_from_read = errno;

		close(http_post->post_fd);
		http_post->post_fd = -1;
		http_post->file_index++;
		/* http_post->file_read is used below so don't clear it here.
		 * It will be cleared when the next file is opened.  */

		if (ret == -1) {
			*error = connection_state_for_errno(errno_from_read);
			return -1;
		} else if (http_post->file_read != file->size) {
			/* ELinks already sent a Content-Length header
			 * based on the size of this file, but the
			 * file has since been shrunk.  Abort the
			 * connection because ELinks can no longer get
			 * enough data to fill the Content-Length.
			 * (Well, it could pad with zeroes, but that
			 * would be just weird.)  */
			*error = connection_state(S_HTTP_UPLOAD_RESIZED);
			return -1;
		} else {
			/* The upload file ended but there may still
			 * be more data in uri.post.  If not,
			 * read_http_post_inline() will return 0 to
			 * indicate the final end of file.  */
			return -2;
		}
	}

	http_post->file_read += ret;
	if (http_post->file_read > file->size) {
		/* ELinks already sent a Content-Length header based
		 * on the size of this file, but the file has since
		 * been extended.  Abort the connection because ELinks
		 * can no longer fit the entire file in the original
		 * Content-Length.  */
		*error = connection_state(S_HTTP_UPLOAD_RESIZED);
		return -1;
	}

	return ret;
}
Beispiel #9
0
void
data_protocol_handler(struct connection *conn)
{
	struct uri *uri = conn->uri;
	struct cache_entry *cached = get_cache_entry(uri);
	unsigned char *data_start, *data;
	int base64 = 0;

	if (!cached) {
		abort_connection(conn, connection_state(S_OUT_OF_MEM));
		return;
	}

	conn->cached = cached;

	data_start = parse_data_protocol_header(conn, &base64);
	if (!data_start) {
		abort_connection(conn, connection_state(S_OUT_OF_MEM));
		return;
	}

	/* Allocate the data string because URI decoding will possibly modify
	 * it. */
	data = memacpy(data_start, uri->datalen - (data_start - uri->data));
	if (!data) {
		abort_connection(conn, connection_state(S_OUT_OF_MEM));
		return;
	}

	if (base64) {
		unsigned char *decoded = base64_encode(data);

		if (!decoded) {
			abort_connection(conn, connection_state(S_OUT_OF_MEM));
			return;
		}

		mem_free_set(&data, decoded);
	} else {
		decode_uri(data);
	}

	{
		/* Use strlen() to get the correct decoded length */
		int datalen = strlen((const char *)data);

		add_fragment(cached, conn->from, data, datalen);
		conn->from += datalen;
	}

	mem_free(data);

	abort_connection(conn, connection_state(S_OK));
}
Beispiel #10
0
static struct connection_state
init_nntp_header(struct connection *conn, struct read_buffer *rb)
{
	struct nntp_connection_info *nntp = conn->info;

	if (!conn->cached) {
		conn->cached = get_cache_entry(conn->uri);
		if (!conn->cached) return connection_state(S_OUT_OF_MEM);

	} else if (conn->cached->head || conn->cached->content_type) {
		/* If the head is set wipe out the content to be sure */
		delete_entry_content(conn->cached);
		mem_free_set(&conn->cached->head, NULL);
	}

	/* XXX: Override any Content-Type line in the header */
	mem_free_set(&conn->cached->content_type, stracpy("text/html"));
	if (!conn->cached->content_type)
		return connection_state(S_OUT_OF_MEM);

	switch (nntp->target) {
	case NNTP_TARGET_ARTICLE_NUMBER:
	case NNTP_TARGET_MESSAGE_ID:
	case NNTP_TARGET_GROUP_MESSAGE_ID:
	{
		unsigned char *end;

		end = get_nntp_message_header_end(rb->data, rb->length);
		if (!end) {
			/* Redo the whole cache entry thing next time */
			return connection_state(S_TRANS);
		}

		/* FIXME: Add the NNTP response code line */
		conn->cached->head = stracpy("FIXME NNTP response code\r\n");
		if (!conn->cached->head) return connection_state(S_OUT_OF_MEM);

		add_to_strn(&conn->cached->head, rb->data);

		/* ... and remove it */
		conn->received += end - rb->data;
		kill_buffer_data(rb, end - rb->data);
		break;
	}
	case NNTP_TARGET_ARTICLE_RANGE:
	case NNTP_TARGET_GROUP:
	case NNTP_TARGET_GROUPS:
	case NNTP_TARGET_QUIT:
		break;
	}

	return connection_state(S_OK);
}
Beispiel #11
0
void
make_connection(struct socket *socket, struct uri *uri,
		socket_connect_T connect_done, int no_cache)
{
	unsigned char *host = get_uri_string(uri, URI_DNS_HOST);
	struct connect_info *connect_info;
	enum dns_result result;
	enum blacklist_flags verify;

	socket->ops->set_timeout(socket, connection_state(0));

	if (!host) {
		socket->ops->retry(socket, connection_state(S_OUT_OF_MEM));
		return;
	}

	connect_info = init_connection_info(uri, socket, connect_done);
	if (!connect_info) {
		mem_free(host);
		socket->ops->retry(socket, connection_state(S_OUT_OF_MEM));
		return;
	}

	socket->connect_info = connect_info;
	/* XXX: Keep here and not in init_connection_info() to make
	 * complete_connect_socket() work from the HTTP implementation. */
	socket->need_ssl = get_protocol_need_ssl(uri->protocol);
	if (!socket->set_no_tls) {
		enum blacklist_flags flags = get_blacklist_flags(uri);
		socket->no_tls = ((flags & SERVER_BLACKLIST_NO_TLS) != 0);
		socket->set_no_tls = 1;
	}

	verify = get_blacklist_flags(uri);
	socket->verify = ((verify & SERVER_BLACKLIST_NO_CERT_VERIFY) == 0);

	debug_transfer_log("\nCONNECTION: ", -1);
	debug_transfer_log(host, -1);
	debug_transfer_log("\n", -1);

	result = find_host(host, &connect_info->dnsquery, (dns_callback_T) dns_found,
			   socket, no_cache);

	mem_free(host);

	if (result == DNS_ASYNC)
		socket->ops->set_state(socket, connection_state(S_DNS));
}
Beispiel #12
0
/* Called when we receive a connection on the listening socket. */
static void
accept_bittorrent_peer_connection(void *____)
{
	struct sockaddr_in addr;
	int peer_sock;
	int addrlen = sizeof(addr);
	struct bittorrent_peer_connection *peer;
	struct read_buffer *buffer;

	peer_sock = accept(bittorrent_socket, (struct sockaddr *) &addr, &addrlen);
	if (peer_sock < 0) return;

	if (set_nonblocking_fd(peer_sock) < 0) {
		close(peer_sock);
		return;
	}

	peer = init_bittorrent_peer_connection(peer_sock);
	if (!peer) {
		close(peer_sock);
		return;
	}

	peer->remote.initiater = 1;

	/* Just return. Failure is handled by alloc_read_buffer(). */
	buffer = alloc_read_buffer(peer->socket);
	if (!buffer) return;

	read_from_socket(peer->socket, buffer, connection_state(S_TRANS),
			 read_bittorrent_peer_handshake);

	add_to_list(bittorrent_peer_connections, peer);
}
Beispiel #13
0
void
about_protocol_handler(struct connection *conn)
{
	struct cache_entry *cached = get_cache_entry(conn->uri);

	/* Only do this the first time */
	if (cached && !cached->content_type) {
#ifndef CONFIG_SMALL
		{
			const struct about_page *page = about_pages;

			for (; page->name; page++) {
				int len;
				unsigned char *str;

				if (strcmp(conn->uri->data, page->name))
					continue;

				str = page->string;
				len = strlen(str);
				add_fragment(cached, 0, str, len);
				conn->from = len;
				break;
			}
		}
#endif

		/* Set content to known type */
		mem_free_set(&cached->content_type, stracpy("text/html"));
	}

	conn->cached = cached;
	abort_connection(conn, connection_state(S_OK));
}
Beispiel #14
0
static void
read_response_from_socket(struct socket *socket)
{
	struct read_buffer *rb = alloc_read_buffer(socket);

	if (rb) read_from_socket(socket, rb, connection_state(S_SENT),
				 socket->read_done);
}
Beispiel #15
0
/* Called when the connection changes state. Usually state starts out being
 * S_DMS (while looking up the host) then moves to S_CONN (while connecting),
 * and should hopefully become S_TRANS (while transfering). Note, state can hold
 * both internally defined connection states as described above and errno
 * values, such as ECONNREFUSED. */
static void
set_bittorrent_socket_state(struct socket *socket, struct connection_state state)
{
	struct bittorrent_peer_connection *peer = socket->conn;

	if (is_in_state(state, S_TRANS) && peer->bittorrent)
		set_connection_state(peer->bittorrent->conn,
				     connection_state(S_TRANS));
}
Beispiel #16
0
static void
check_if_closed(struct socket *socket, struct read_buffer *rb)
{
	if (socket->state == SOCKET_CLOSED) {
		abort_connection((struct connection *)socket->conn, connection_state(S_OK));
		return;
	}
	http_got_header(socket, rb);
}
Beispiel #17
0
static void
smb_got_error(struct socket *socket, struct read_buffer *rb)
{
	int len = rb->length;
	struct connection *conn = socket->conn;
	struct connection_state error;

	if (len < 0) {
		abort_connection(conn, connection_state_for_errno(errno));
		return;
	}

	/* There should be free space in the buffer, because
	 * @alloc_read_buffer allocated several kibibytes, and the
	 * child process wrote only an integer and a newline to the
	 * pipe.  */
	assert(rb->freespace >= 1);
	if_assert_failed {
		abort_connection(conn, connection_state(S_INTERNAL));
		return;
	}
	rb->data[len] = '\0';
	switch (rb->data[0]) {
	case 'S':
		error = connection_state_for_errno(atoi(rb->data + 1));
		break;
	case 'I':
		error = connection_state(atoi(rb->data + 1));
		break;
	default:
		ERROR("malformed error code: %s", rb->data);
		error = connection_state(S_INTERNAL);
		break;
	}
	kill_buffer_data(rb, len);

	if (is_system_error(error) && error.syserr == EACCES)
		prompt_username_pw(conn);
	else
		abort_connection(conn, error);
}
Beispiel #18
0
/** @return -2 if no data was read but the caller should retry;
 * -1 if an error occurred and *@a error was set; 0 at end of data;
 * a positive number if that many bytes were read.
 *
 * @relates http_post */
static int
read_http_post_inline(struct http_post *http_post,
		      unsigned char buffer[], int max,
		      struct connection_state *error)
{
	const unsigned char *post = http_post->post_data;
	const unsigned char *end = (const unsigned char *)strchr((char *)post, FILE_CHAR);
	int total = 0;

	assert(http_post->post_fd < 0);
	if_assert_failed { *error = connection_state(S_INTERNAL); return -1; }

	if (!end)
		end = (const unsigned char *)strchr((char *)post, '\0');

	while (post < end && total < max) {
		int h1, h2;

		h1 = unhx(post[0]);
		assertm(h1 >= 0 && h1 < 16, "h1 in the POST buffer is %d (%d/%c)", h1, post[0], post[0]);
		if_assert_failed h1 = 0;

		h2 = unhx(post[1]);
		assertm(h2 >= 0 && h2 < 16, "h2 in the POST buffer is %d (%d/%c)", h2, post[1], post[1]);
		if_assert_failed h2 = 0;

		buffer[total++] = (h1<<4) + h2;
		post += 2;
	}
	if (post != end || *end != FILE_CHAR) {
		http_post->post_data = post;
		return total;
	}

	http_post->file_read = 0;
	end = (const unsigned char *)strchr((char *)(post + 1), FILE_CHAR);
	assert(end);
	http_post->post_fd = open((const char *)http_post->files[http_post->file_index].name,
				  O_RDONLY);
	/* Be careful not to change errno here.  */
	if (http_post->post_fd < 0) {
		http_post->post_data = post;
		if (total > 0)
			return total; /* retry the open on the next call */
		else {
			*error = connection_state_for_errno(errno);
			return -1;
		}
	}
	http_post->post_data = end + 1;
	return total ? total : -2;
}
Beispiel #19
0
void
timeout_socket(struct socket *socket)
{
	if (!socket->connect_info) {
		socket->ops->retry(socket, connection_state(S_TIMEOUT));
		return;
	}

	/* Is the DNS resolving still in progress? */
	if (socket->connect_info->dnsquery) {
		socket->ops->done(socket, connection_state(S_TIMEOUT));
		return;
	}

	/* Try the next address, */
	connect_socket(socket, connection_state(S_TIMEOUT));

	/* Reset the timeout if connect_socket() started a new attempt
	 * to connect. */
	if (socket->connect_info)
		socket->ops->set_timeout(socket, connection_state(0));
}
Beispiel #20
0
struct read_buffer *
alloc_read_buffer(struct socket *socket)
{
	struct read_buffer *rb;

	rb = mem_calloc(1, RD_SIZE(rb, 0));
	if (!rb) {
		socket->ops->done(socket, connection_state(S_OUT_OF_MEM));
		return NULL;
	}

	rb->freespace = RD_SIZE(rb, 0) - sizeof(*rb);

	return rb;
}
Beispiel #21
0
void
write_to_socket(struct socket *socket, unsigned char *data, int len,
		struct connection_state state, socket_write_T write_done)
{
	select_handler_T read_handler;
	struct write_buffer *wb;

	debug_transfer_log(data, len);

	assert(len > 0);
	if_assert_failed return;

	socket->ops->set_timeout(socket, connection_state(0));

	wb = mem_alloc(sizeof(*wb) + len);
	if (!wb) {
		socket->ops->done(socket, connection_state(S_OUT_OF_MEM));
		return;
	}

	wb->length = len;
	wb->pos = 0;
	wb->done = write_done;
	memcpy(wb->data, data, len);
	mem_free_set(&socket->write_buffer, wb);

	if (socket->duplex) {
		read_handler = get_handler(socket->fd, SELECT_HANDLER_READ);
	} else {
		read_handler = NULL;
	}

	set_handlers(socket->fd, read_handler, (select_handler_T) write_select,
		     (select_handler_T) exception, socket);
	socket->ops->set_state(socket, state);
}
Beispiel #22
0
void
complete_connect_socket(struct socket *socket, struct uri *uri,
			socket_connect_T done)
{
	struct connect_info *connect_info = socket->connect_info;

	if (connect_info && connect_info->uri) {
		/* Remember whether the server supported TLS or not.
		 * Then the next request can immediately use the right
		 * protocol.  This is important for HTTP POST requests
		 * because it is not safe to silently retry them.  The
		 * uri parameter is normally NULL here so don't use it.  */
		if (socket->no_tls)
			add_blacklist_entry(connect_info->uri,
					    SERVER_BLACKLIST_NO_TLS);
		else
			del_blacklist_entry(connect_info->uri,
					    SERVER_BLACKLIST_NO_TLS);
	}

	/* This is a special case used by the HTTP implementation to acquire an
	 * SSL link for handling CONNECT requests. */
	if (!connect_info) {
		assert(uri && socket);
		connect_info = init_connection_info(uri, socket, done);
		if (!connect_info) {
			socket->ops->done(socket, connection_state(S_OUT_OF_MEM));
			return;
		}

		socket->connect_info = connect_info;
	}

#ifdef CONFIG_SSL
	/* Check if the connection should run over an encrypted link */
	if (socket->need_ssl
	    && !socket->ssl
	    && ssl_connect(socket) < 0)
		return;
#endif

	if (connect_info->done)
		connect_info->done(socket);

	done_connection_info(socket);
}
Beispiel #23
0
static void
get_request(struct connection *conn)
{
	struct read_buffer *rb = alloc_read_buffer(conn->socket);

	if (!rb) return;

	memcpy(rb->data, "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\n\r\n", 45);
	rb->length = 45;
	rb->freespace -= 45;

	conn->unrestartable = 1;

	conn->socket->state = SOCKET_END_ONCLOSE;
	read_from_socket(conn->socket, rb, connection_state(S_SENT),
			 http_got_header);
}
Beispiel #24
0
static void
read_from_stdin(struct connection *conn)
{
	struct read_buffer *rb = alloc_read_buffer(conn->socket);

	if (!rb) return;

	memcpy(rb->data, "HTTP/1.0 200 OK\r\n\r\n", 19);
	rb->length = 19;
	rb->freespace -= 19;

	conn->unrestartable = 1;

	conn->socket->state = SOCKET_END_ONCLOSE;
	read_from_socket(conn->socket, rb, connection_state(S_SENT),
			check_if_closed);
}
Beispiel #25
0
struct connection_state
read_nntp_response_data(struct connection *conn, struct read_buffer *rb)
{
	struct string html;
	unsigned char *end;
	struct connection_state state = connection_state(S_TRANS);

	if (conn->from == 0) {
		switch (init_nntp_header(conn, rb).basic) {
		case S_OK:
			break;

		case S_OUT_OF_MEM:
			return connection_state(S_OUT_OF_MEM);

		case S_TRANS:
			return connection_state(S_TRANS);

		default:
			return connection_state(S_NNTP_ERROR);
		}
	}

	if (!init_string(&html))
		return connection_state(S_OUT_OF_MEM);

	if (conn->from == 0)
		add_nntp_html_start(&html, conn);

	while ((end = get_nntp_line_end(rb->data, rb->length))) {
		unsigned char *line = check_nntp_line(rb->data, end);

		if (!line) {
			state = connection_state(S_OK);
			break;
		}

		add_nntp_html_line(&html, conn, line);

		conn->received += end - rb->data;
		kill_buffer_data(rb, end - rb->data);
	}

	if (!is_in_state(state, S_TRANS))
		add_nntp_html_end(&html, conn);

	add_fragment(conn->cached, conn->from, html.source, html.length);

	conn->from += html.length;
	done_string(&html);

	return state;
}
Beispiel #26
0
static void
smb_directory(int dir, struct string *prefix, struct uri *uri)
{
	struct string buf;
	struct directory_entry *entries;

	if (!is_in_state(init_directory_listing(&buf, uri), S_OK)) {
		smb_error(connection_state(S_OUT_OF_MEM));
	}

	fputs("text/html", header_out);
	fclose(header_out);

	entries = get_smb_directory_entries(dir, prefix);
	add_smb_dir_entries(entries, NULL, &buf);
	add_to_string(&buf, "</pre><hr/></body></html>\n");

	fputs(buf.source, data_out);
	done_string(&buf);
	exit(0);
}
Beispiel #27
0
void timeout_socket( struct socket *socket )
{
  int eax;
  if ( socket->connect_info == 0 )
  {
    connection_state( S_TIMEOUT );
    esi( socket[0].fd );
    return;
  }
  else
  {
    if ( socket->connect_info->dnsquery )
    {
      if ( assert_failed == 0 )
        assert_failed = 0;
        eax( socket[0].fd, (long long)-100010 );
        return;
    }
    else
    {
      if ( assert_failed == 0 )
        assert_failed = 0;
      else
        assert_failed = 0;
      connect_socket( &socket[0], (long long)-100003 );
      if ( socket->connect_info )
      {
        if ( assert_failed == 0 )
          assert_failed = 0;
      }
      else
      {
        return;
      }
    }
    assert_failed = 0;
  }
}
Beispiel #28
0
void
read_from_socket(struct socket *socket, struct read_buffer *buffer,
		 struct connection_state state, socket_read_T done)
{
	const int is_buffer_new = (buffer != socket->read_buffer);
	struct socket_weak_ref ref;
	select_handler_T write_handler;

	ref.socket = socket;
	add_to_list(socket_weak_refs, &ref);

	buffer->done = done;

	socket->ops->set_timeout(socket, connection_state(0));
	socket->ops->set_state(socket, state);

	del_from_list(&ref);
	if (ref.socket == NULL) {
		/* socket->ops->set_state deleted the socket. */
		if (is_buffer_new)
			mem_free(buffer);
		return;
	}

	if (socket->read_buffer && buffer != socket->read_buffer)
		mem_free(socket->read_buffer);
	socket->read_buffer = buffer;

	if (socket->duplex) {
		write_handler = get_handler(socket->fd, SELECT_HANDLER_WRITE);
	} else {
		write_handler = NULL;
	}

	set_handlers(socket->fd, (select_handler_T) read_select, write_handler,
		     (select_handler_T) exception, socket);
}
Beispiel #29
0
void
mailcap_protocol_handler(struct connection *conn)
{
#ifdef HAVE_FORK
	unsigned char *script, *ref;
	pid_t pid;
	struct connection_state state = connection_state(S_OK);
	int pipe_read[2], check;

	/* security checks */
	if (!conn->referrer || conn->referrer->protocol != PROTOCOL_MAILCAP) {
		goto bad;
	}
	ref = get_uri_string(conn->referrer, URI_DATA);
	if (!ref) {
		goto bad;
	}
	check = strcmp(ref, "elmailcap");
	mem_free(ref);
	if (check) goto bad;
	
	script = get_uri_string(conn->uri, URI_DATA);
	if (!script) {
		state = connection_state(S_OUT_OF_MEM);
		goto end2;
	}

	if (c_pipe(pipe_read)) {
		state = connection_state_for_errno(errno);
		goto end1;
	}

	pid = fork();
	if (pid < 0) {
		state = connection_state_for_errno(errno);
		goto end0;
	}
	if (!pid) {
		if (dup2(pipe_read[1], STDOUT_FILENO) < 0) {
			_exit(2);
		}
		/* We implicitly chain stderr to ELinks' stderr. */
		close_all_non_term_fd();

		if (execl("/bin/sh", "/bin/sh", "-c", script, (char *) NULL)) {
			_exit(3);
		}

	} else { /* ELinks */
		mem_free(script);

		if (!init_http_connection_info(conn, 1, 0, 1)) {
			close(pipe_read[0]); close(pipe_read[1]);
			return;
		}

		close(pipe_read[1]);
		conn->socket->fd = pipe_read[0];

		conn->data_socket->fd = -1;
		conn->cgi = 1;
		set_nonblocking_fd(conn->socket->fd);

		get_request(conn);
		return;
	}

end0:
	close(pipe_read[0]); close(pipe_read[1]);
end1:
	mem_free(script);
end2:
	abort_connection(conn, state);
	return;
#endif
bad:
	abort_connection(conn, connection_state(S_BAD_URL));
}
Beispiel #30
0
void
smb_protocol_handler(struct connection *conn)
{
	int smb_pipe[2] = { -1, -1 };
	int header_pipe[2] = { -1, -1 };
	pid_t cpid;

	if (c_pipe(smb_pipe) || c_pipe(header_pipe)) {
		int s_errno = errno;

		if (smb_pipe[0] >= 0) close(smb_pipe[0]);
		if (smb_pipe[1] >= 0) close(smb_pipe[1]);
		if (header_pipe[0] >= 0) close(header_pipe[0]);
		if (header_pipe[1] >= 0) close(header_pipe[1]);
		abort_connection(conn, connection_state_for_errno(s_errno));
		return;
	}
	conn->from = 0;
	conn->unrestartable = 1;
	find_auth(conn->uri); /* remember username and password */

	cpid = fork();
	if (cpid == -1) {
		int s_errno = errno;

		close(smb_pipe[0]);
		close(smb_pipe[1]);
		close(header_pipe[0]);
		close(header_pipe[1]);
		retry_connection(conn, connection_state_for_errno(s_errno));
		return;
	}

	if (!cpid) {
		dup2(open("/dev/null", O_RDONLY), 0);
		close(1);
		close(2);
		data_out = fdopen(smb_pipe[1], "w");
		header_out = fdopen(header_pipe[1], "w");

		if (!data_out || !header_out) exit(1);

		close(smb_pipe[0]);
		close(header_pipe[0]);

		/* There may be outgoing data in stdio buffers
		 * inherited from the parent process.  The parent
		 * process is going to write this data, so the child
		 * process must not do that.  Closing the file
		 * descriptors ensures this.
		 *
		 * FIXME: If something opens more files and gets the
		 * same file descriptors and does not close them
		 * before exit(), then stdio may attempt to write the
		 * buffers to the wrong files.  This might happen for
		 * example if libsmbclient calls syslog().  */

		close_all_fds_but_two(smb_pipe[1], header_pipe[1]);
		do_smb(conn);

	} else {
		struct read_buffer *buf2;

		conn->data_socket->fd = smb_pipe[0];
		conn->socket->fd = header_pipe[0];
		set_nonblocking_fd(conn->data_socket->fd);
		set_nonblocking_fd(conn->socket->fd);
		close(smb_pipe[1]);
		close(header_pipe[1]);
		buf2 = alloc_read_buffer(conn->socket);
		if (!buf2) {
			close_socket(conn->data_socket);
			close_socket(conn->socket);
			abort_connection(conn, connection_state(S_OUT_OF_MEM));
			return;
		}
		read_from_socket(conn->socket, buf2,
				 connection_state(S_CONN), smb_got_header);
	}
}