Пример #1
0
static int get_ftp_response(struct connection *c, struct read_buffer *rb, int part)
{
    int l;
    set_timeout(c);
again:
    for (l = 0; l < rb->len; l++) if (rb->data[l] == 10) {
            unsigned char *e;
            long k = strtoul(cast_const_char rb->data, (char **)(void *)&e, 10);
            if (e != rb->data + 3 || k < 100 || k >= 1000) return -1;
            if (*e == '-') {
                int i;
                for (i = 0; i < rb->len - 5; i++) {
                    if (rb->data[i] == 10 && !memcmp(rb->data+i+1, rb->data, 3) && rb->data[i+4] == ' ') {
                        for (i++; i < rb->len; i++) if (rb->data[i] == 10) goto ok;
                        return 0;
                    }
                }
                return 0;
ok:
                l = i;
            }
            if (!part && k >= 100 && k < 200) {
                kill_buffer_data(rb, l + 1);
                goto again;
            }
            if (part == 2) return k;
            kill_buffer_data(rb, l + 1);
            return k;
        }
    return 0;
}
Пример #2
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);
}
Пример #3
0
void finger_get_response(struct connection *c, struct read_buffer *rb)
{
	struct cache_entry *e;
	int l;
	set_timeout(c);
	if (get_cache_entry(c->url, &e)) {
		setcstate(c, S_OUT_OF_MEM);
		abort_connection(c);
		return;
	}
	c->cache = e;
	if (rb->close == 2) {
		setcstate(c, S_OK);
		finger_end_request(c);
		return;
	}
	l = rb->len;
	if (c->from + l < 0) {
		setcstate(c, S_LARGE_FILE);
		abort_connection(c);
		return;
	}
	c->received += l;
	if (add_fragment(c->cache, c->from, rb->data, l) == 1) c->tries = 0;
	c->from += l;
	kill_buffer_data(rb, l);
	read_from_socket(c, c->sock1, rb, finger_get_response);
	setcstate(c, S_TRANS);
}
Пример #4
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);
}
Пример #5
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;
}
Пример #6
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);
}
Пример #7
0
enum nntp_code
get_nntp_response_code(struct connection *conn, struct read_buffer *rb)
{
	struct nntp_connection_info *nntp = conn->info;
	unsigned char *line = rb->data;
	unsigned char *end = get_nntp_line_end(rb->data, rb->length);
	enum nntp_code code;
	int linelen;

	if (!end) return NNTP_CODE_NONE;

	/* Just to be safe NUL terminate the line */
	end[-1] = 0;

	linelen = end - line;

	if (linelen < sizeof("xxx\r\n") - 1
	    || !isdigit(line[0])
	    || !isdigit(line[1])
	    || !isdigit(line[2])
	    ||  isdigit(line[3]))
		return NNTP_CODE_INVALID;

	code = atoi(line);

	if (!check_nntp_code_valid(code))
		return NNTP_CODE_INVALID;

	/* Only when listing all articles in group the parameters is needed */
	if (code == NNTP_CODE_211_GROUP_SELECTED
	    && nntp->target == NNTP_TARGET_GROUP
	    && !parse_nntp_group_parameters(nntp, line + 4, end))
		return NNTP_CODE_INVALID;

	/* Remove the response line */
	kill_buffer_data(rb, linelen);

	conn->received += linelen;

	return code;
}
static void finger_get_response(struct connection *c, struct read_buffer *rb)
{
	int l;
	int a;
	set_timeout(c);
	if (!c->cache) {
		if (get_cache_entry(c->url, &c->cache)) {
			setcstate(c, S_OUT_OF_MEM);
			abort_connection(c);
			return;
		}
		c->cache->refcount--;
	}
	if (rb->close == 2) {
		finger_end_request(c, S__OK);
		return;
	}
	l = rb->len;
	if ((off_t)(0UL + c->from + l) < 0) {
		setcstate(c, S_LARGE_FILE);
		abort_connection(c);
		return;
	}
	c->received += l;
	a = add_fragment(c->cache, c->from, rb->data, l);
	if (a < 0) {
		setcstate(c, a);
		abort_connection(c);
		return;
	}
	if (a == 1) c->tries = 0;
	c->from += l;
	kill_buffer_data(rb, l);
	read_from_socket(c, c->sock1, rb, finger_get_response);
	setcstate(c, S_TRANS);
}
Пример #9
0
void http_got_header(struct connection *c, struct read_buffer *rb)
{
    int cf;
    int state = c->state != S_PROC ? S_GETH : S_PROC;
    unsigned char *head;
    unsigned char *cookie, *ch;
    int a, h, version;
    unsigned char *d;
    struct cache_entry *e;
    struct http_connection_info *info;
    unsigned char *host = upcase(c->url[0]) != 'P' ? c->url : get_url_data(c->url);
    set_timeout(c);
    info = c->info;
    if (rb->close == 2) {
        unsigned char *h;
        if (!c->tries && (h = get_host_name(host))) {
            if (info->bl_flags & BL_NO_CHARSET) {
                del_blacklist_entry(h, BL_NO_CHARSET);
            } else {
                add_blacklist_entry(h, BL_NO_CHARSET);
                c->tries = -1;
            }
            mem_free(h);
        }
        setcstate(c, S_CANT_READ);
        retry_connection(c);
        return;
    }
    rb->close = 0;
again:
    if ((a = get_header(rb)) == -1) {
        setcstate(c, S_HTTP_ERROR);
        abort_connection(c);
        return;
    }
    if (!a) {
        read_from_socket(c, c->sock1, rb, http_got_header);
        setcstate(c, state);
        return;
    }
    if (a != -2) {
        head = mem_alloc(a + 1);
        memcpy(head, rb->data, a);
        head[a] = 0;
        kill_buffer_data(rb, a);
    } else {
        head = stracpy("HTTP/0.9 200 OK\r\nContent-Type: text/html\r\n\r\n");
    }
    if (get_http_code(head, &h, &version) || h == 101) {
        mem_free(head);
        setcstate(c, S_HTTP_ERROR);
        abort_connection(c);
        return;
    }
    if (check_http_server_bugs(host, c->info, head) && is_connection_restartable(c)) {
        mem_free(head);
        setcstate(c, S_RESTART);
        retry_connection(c);
        return;
    }
    ch = head;
    while ((cookie = parse_http_header(ch, "Set-Cookie", &ch))) {
        unsigned char *host = upcase(c->url[0]) != 'P' ? c->url : get_url_data(c->url);
        set_cookie(NULL, host, cookie);
        mem_free(cookie);
    }
    if (h == 100) {
        mem_free(head);
        state = S_PROC;
        goto again;
    }
    if (h < 200) {
        mem_free(head);
        setcstate(c, S_HTTP_ERROR);
        abort_connection(c);
        return;
    }
    if (h == 204) {
        mem_free(head);
        setcstate(c, S_HTTP_204);
        http_end_request(c, 0);
        return;
    }
    if (h == 304) {
        mem_free(head);
        setcstate(c, S_OK);
        http_end_request(c, 1);
        return;
    }
    if ((h == 500 || h == 502 || h == 503 || h == 504) && http_bugs.retry_internal_errors && is_connection_restartable(c)) {
        /* !!! FIXME: wait some time ... */
        mem_free(head);
        setcstate(c, S_RESTART);
        retry_connection(c);
        return;
    }
    if (!c->cache && get_cache_entry(c->url, &c->cache)) {
        mem_free(head);
        setcstate(c, S_OUT_OF_MEM);
        abort_connection(c);
        return;
    }
    e = c->cache;
    e->http_code = h;
    if (e->head) mem_free(e->head);
    e->head = head;
    if ((d = parse_http_header(head, "Expires", NULL))) {
        time_t t = parse_http_date(d);
        if (t && e->expire_time != 1) e->expire_time = t;
        mem_free(d);
    }
    if ((d = parse_http_header(head, "Pragma", NULL))) {
        if (!casecmp(d, "no-cache", 8)) e->expire_time = 1;
        mem_free(d);
    }
    if ((d = parse_http_header(head, "Cache-Control", NULL))) {
        char *f = d;
        while (1) {
            while (*f && (*f == ' ' || *f == ',')) f++;
            if (!*f) break;
            if (!casecmp(f, "no-cache", 8) || !casecmp(f, "must-revalidate", 15)) {
                e->expire_time = 1;
            }
            if (!casecmp(f, "max-age=", 8)) {
                if (e->expire_time != 1) e->expire_time = time(NULL) + atoi(f + 8);
            }
            while (*f && *f != ',') f++;
        }
        mem_free(d);
    }
#ifdef HAVE_SSL
    if (c->ssl) {
        int l = 0;
        if (e->ssl_info) mem_free(e->ssl_info);
        e->ssl_info = init_str();
        add_num_to_str(&e->ssl_info, &l, SSL_get_cipher_bits(c->ssl, NULL));
        add_to_str(&e->ssl_info, &l, "-bit ");
        add_to_str(&e->ssl_info, &l, SSL_get_cipher_version(c->ssl));
        add_to_str(&e->ssl_info, &l, " ");
        add_to_str(&e->ssl_info, &l, (unsigned  char *)SSL_get_cipher_name(c->ssl));
    }
#endif
    if (e->redirect) mem_free(e->redirect), e->redirect = NULL;
    if (h == 301 || h == 302 || h == 303 || h == 307) {
        if ((h == 302 || h == 307) && !e->expire_time) e->expire_time = 1;
        if ((d = parse_http_header(e->head, "Location", NULL))) {
            unsigned char *user, *ins;
            unsigned char *newuser, *newpassword;
            if (!parse_url(d, NULL, &user, NULL, NULL, NULL, &ins, NULL, NULL, NULL, NULL, NULL, NULL) && !user && ins && (newuser = get_user_name(host))) {
                if (*newuser) {
                    int ins_off = ins - d;
                    newpassword = get_pass(host);
                    if (!newpassword) newpassword = stracpy("");
                    add_to_strn(&newuser, ":");
                    add_to_strn(&newuser, newpassword);
                    add_to_strn(&newuser, "@");
                    extend_str(&d, strlen(newuser));
                    ins = d + ins_off;
                    memmove(ins + strlen(newuser), ins, strlen(ins) + 1);
                    memcpy(ins, newuser, strlen(newuser));
                    mem_free(newpassword);
                }
                mem_free(newuser);
            }
            if (e->redirect) mem_free(e->redirect);
            e->redirect = d;
            e->redirect_get = h == 303;
        }
    }
    if (!e->expire_time && strchr(c->url, POST_CHAR)) e->expire_time = 1;
    info->close = 0;
    info->length = -1;
    info->version = version;
    if ((d = parse_http_header(e->head, "Connection", NULL)) || (d = parse_http_header(e->head, "Proxy-Connection", NULL))) {
        if (!strcasecmp(d, "close")) info->close = 1;
        mem_free(d);
    } else if (version < 11) info->close = 1;
    cf = c->from;
    c->from = 0;
    if ((d = parse_http_header(e->head, "Content-Range", NULL))) {
        if (strlen(d) > 6) {
            d[5] = 0;
            if (!(strcasecmp(d, "bytes")) && d[6] >= '0' && d[6] <= '9') {
#if defined(HAVE_STRTOLL)
                long long f = strtoll(d + 6, NULL, 10);
#elif defined(HAVE_STRTOQ)
                longlong f = strtoq(d + 6, NULL, 10);
#else
                long f = strtol(d + 6, NULL, 10);
                if (f == MAXLONG) f = -1;
#endif
                if (f >= 0 && (off_t)f >= 0 && (off_t)f == f) c->from = f;
            }
        }
        mem_free(d);
    }
    if (cf && !c->from && !c->unrestartable) c->unrestartable = 1;
    if (c->from > cf || c->from < 0) {
        setcstate(c, S_HTTP_ERROR);
        abort_connection(c);
        return;
    }
    if ((d = parse_http_header(e->head, "Content-Length", NULL))) {
        unsigned char *ep;
#if defined(HAVE_STRTOLL)
        long long l = strtoll(d, (char **)(void *)&ep, 10);
#elif defined(HAVE_STRTOQ)
        longlong l = strtoq(d, (char **)(void *)&ep, 10);
#else
        long l = strtol(d, (char **)(void *)&ep, 10);
        if (l == MAXLONG) l = -1;
#endif
        if (!*ep && l >= 0 && (off_t)l >= 0 && (off_t)l == l) {
            if (!info->close || version >= 11) info->length = l;
            if (c->from + l >= 0) c->est_length = c->from + l;
        }
        mem_free(d);
    }
    if ((d = parse_http_header(e->head, "Accept-Ranges", NULL))) {
        if (!strcasecmp(d, "none") && !c->unrestartable) c->unrestartable = 1;
        mem_free(d);
    } else {
        if (!c->unrestartable && !c->from) c->unrestartable = 1;
    }
    if (info->bl_flags & BL_NO_RANGE && !c->unrestartable) c->unrestartable = 1;
    if ((d = parse_http_header(e->head, "Transfer-Encoding", NULL))) {
        if (!strcasecmp(d, "chunked")) {
            info->length = -2;
            info->chunk_remaining = -1;
        }
        mem_free(d);
    }
    if (!info->close && info->length == -1) info->close = 1;
    if ((d = parse_http_header(e->head, "Last-Modified", NULL))) {
        if (e->last_modified && strcasecmp(e->last_modified, d)) {
            delete_entry_content(e);
            if (c->from) {
                c->from = 0;
                mem_free(d);
                setcstate(c, S_MODIFIED);
                retry_connection(c);
                return;
            }
        }
        if (!e->last_modified) e->last_modified = d;
        else mem_free(d);
    }
    if (!e->last_modified && (d = parse_http_header(e->head, "Date", NULL)))
        e->last_modified = d;
    if (info->length == -1 || (version < 11 && info->close)) rb->close = 1;
    read_http_data(c, rb);
}
Пример #10
0
void read_http_data(struct connection *c, struct read_buffer *rb)
{
    struct http_connection_info *info = c->info;
    set_timeout(c);
    if (rb->close == 2) {
        setcstate(c, S_OK);
        http_end_request(c, 0);
        return;
    }
    if (info->length != -2) {
        int l = rb->len;
        if (info->length >= 0 && info->length < l) l = info->length;
        if (c->from + l < 0) {
            setcstate(c, S_LARGE_FILE);
            abort_connection(c);
            return;
        }
        c->received += l;
        if (add_fragment(c->cache, c->from, rb->data, l) == 1) c->tries = 0;
        if (info->length >= 0) info->length -= l;
        c->from += l;
        kill_buffer_data(rb, l);
        if (!info->length && !rb->close) {
            setcstate(c, S_OK);
            http_end_request(c, 0);
            return;
        }
    } else {
next_chunk:
        if (info->chunk_remaining == -2) {
            int l;
            if ((l = is_line_in_buffer(rb))) {
                if (l == -1) {
                    setcstate(c, S_HTTP_ERROR);
                    abort_connection(c);
                    return;
                }
                kill_buffer_data(rb, l);
                if (l <= 2) {
                    setcstate(c, S_OK);
                    http_end_request(c, 0);
                    return;
                }
                goto next_chunk;
            }
        } else if (info->chunk_remaining == -1) {
            int l;
            if ((l = is_line_in_buffer(rb))) {
                unsigned char *de;
                long n = 0;	/* warning, go away */
                if (l != -1) n = strtol(rb->data, (char **)(void *)&de, 16);
                if (l == -1 || n < 0 || n >= MAXINT || de == rb->data) {
                    setcstate(c, S_HTTP_ERROR);
                    abort_connection(c);
                    return;
                }
                kill_buffer_data(rb, l);
                if (!(info->chunk_remaining = n)) info->chunk_remaining = -2;
                goto next_chunk;
            }
        } else {
            int l = info->chunk_remaining;
            if (l > rb->len) l = rb->len;
            if (c->from + l < 0) {
                setcstate(c, S_LARGE_FILE);
                abort_connection(c);
                return;
            }
            c->received += l;
            if (add_fragment(c->cache, c->from, rb->data, l) == 1) c->tries = 0;
            info->chunk_remaining -= l;
            c->from += l;
            kill_buffer_data(rb, l);
            if (!info->chunk_remaining && rb->len >= 1) {
                if (rb->data[0] == 10) kill_buffer_data(rb, 1);
                else {
                    if (rb->data[0] != 13 || (rb->len >= 2 && rb->data[1] != 10)) {
                        setcstate(c, S_HTTP_ERROR);
                        abort_connection(c);
                        return;
                    }
                    if (rb->len < 2) goto read_more;
                    kill_buffer_data(rb, 2);
                }
                info->chunk_remaining = -1;
                goto next_chunk;
            }
        }

    }
read_more:
    read_from_socket(c, c->sock1, rb, read_http_data);
    setcstate(c, S_TRANS);
}