コード例 #1
0
static void ftp_got_banner(struct connection *c, struct read_buffer *rb)
{
    int g = get_ftp_response(c, rb, 0);
    if (g == -1) {
        setcstate(c, S_FTP_ERROR);
        abort_connection(c);
        return;
    }
    if (!g) {
        read_from_socket(c, c->sock1, rb, ftp_got_banner);
        return;
    }
    if (g >= 400) {
        setcstate(c, S_FTP_UNAVAIL);
        retry_connection(c);
        return;
    }
    ftp_login(c);
}
コード例 #2
0
ファイル: tcp.c プロジェクト: rsalveti/zephyr
static void tcp_retry_expired(struct k_timer *timer)
{
	struct net_tcp *tcp = CONTAINER_OF(timer, struct net_tcp, retry_timer);
	struct net_pkt *pkt;

	/* Double the retry period for exponential backoff and resent
	 * the first (only the first!) unack'd packet.
	 */
	if (!sys_slist_is_empty(&tcp->sent_list)) {
		tcp->retry_timeout_shift++;

		if (tcp->retry_timeout_shift > CONFIG_NET_TCP_RETRY_COUNT) {
			abort_connection(tcp);
			return;
		}

		k_timer_start(&tcp->retry_timer, retry_timeout(tcp), 0);

		pkt = CONTAINER_OF(sys_slist_peek_head(&tcp->sent_list),
				   struct net_pkt, sent_list);

		if (net_pkt_sent(pkt)) {
			do_ref_if_needed(tcp, pkt);
			net_pkt_set_sent(pkt, false);
		}

		net_pkt_set_queued(pkt, true);

		if (net_tcp_send_pkt(pkt) < 0 && !is_6lo_technology(pkt)) {
			NET_DBG("[%p] pkt %p send failed", tcp, pkt);
			net_pkt_unref(pkt);
		} else {
			NET_DBG("[%p] sent pkt %p", tcp, pkt);
			if (IS_ENABLED(CONFIG_NET_STATISTICS_TCP) &&
			    !is_6lo_technology(pkt)) {
				net_stats_update_tcp_seg_rexmit();
			}
		}
	} else if (IS_ENABLED(CONFIG_NET_TCP_TIME_WAIT)) {
コード例 #3
0
ファイル: file.c プロジェクト: Gingar/port
void file_func(struct connection *c)
{
	struct cache_entry *e;
	unsigned char *file, *name, *head;
	int fl;
	DIR *d;
	int h, r;
	struct stat stt;
	if (anonymous && !anonymousGinga) {
		setcstate(c, S_BAD_URL);
		abort_connection(c);
		return;
	}
	if (!(name = get_filename(c->url))) {
		setcstate(c, S_OUT_OF_MEM); abort_connection(c); return;
	}
	
	if (anonymousGinga && !allowedPath(name)){
		setcstate(c, S_BAD_URL);
		abort_connection(c);
		return;
	}

	if (stat(name, &stt)) {
		mem_free(name);
		setcstate(c, -errno); abort_connection(c); return;
	}
	if (!S_ISDIR(stt.st_mode) && !S_ISREG(stt.st_mode)) {
		mem_free(name);
		setcstate(c, S_FILE_TYPE); abort_connection(c); return;
	}
	if ((h = open(name, O_RDONLY | O_NOCTTY)) == -1) {
		int er = errno;
		if ((d = opendir(name))) goto dir;
		mem_free(name);
		setcstate(c, -er); abort_connection(c); return;
	}
	set_bin(h);
	if (S_ISDIR(stt.st_mode)) {
		struct dirs *dir;
		int dirl;
		int i;
		struct dirent *de;
		d = opendir(name);
		close(h);
		if (!d) {
			mem_free(name);
			setcstate(c, -errno); abort_connection(c); return;
		}
		dir:
		dir = DUMMY, dirl = 0;
		if (name[0] && !dir_sep(name[strlen(name) - 1])) {
			if (get_cache_entry(c->url, &e)) {
				mem_free(name);
				closedir(d);
				setcstate(c, S_OUT_OF_MEM); abort_connection(c); return;
			}
			c->cache = e;
			if (e->redirect) mem_free(e->redirect);
			e->redirect = stracpy(c->url);
			e->redirect_get = 1;
			add_to_strn(&e->redirect, "/");
			mem_free(name);
			closedir(d);
			goto end;
		}
		last_uid = -1;
		last_gid = -1;
		file = init_str();
		fl = 0;
		add_to_str(&file, &fl, "<html><head><title>");
		add_conv_str(&file, &fl, name, strlen(name), -1);
		add_to_str(&file, &fl, "</title></head><body><h2>Directory ");
		add_conv_str(&file, &fl, name, strlen(name), -1);
		add_to_str(&file, &fl, "</h2><pre>");
		while ((de = readdir(d))) {
			struct stat stt, *stp;
			unsigned char **p;
			int l;
			unsigned char *n;
			if (!strcmp(de->d_name, ".")) continue;
			if ((unsigned)dirl > MAXINT / sizeof(struct dirs) - 1) overalloc();
			dir = mem_realloc(dir, (dirl + 1) * sizeof(struct dirs));
			dir[dirl].f = stracpy(de->d_name);
			*(p = &dir[dirl++].s) = init_str();
			l = 0;
			n = stracpy(name);
			add_to_strn(&n, de->d_name);
#ifdef FS_UNIX_SOFTLINKS
			if (lstat(n, &stt))
#else
			if (stat(n, &stt))
#endif
			     stp = NULL;
			else stp = &stt;
			mem_free(n);
			stat_mode(p, &l, stp);
			stat_links(p, &l, stp);
			stat_user(p, &l, stp, 0);
			stat_user(p, &l, stp, 1);
			stat_size(p, &l, stp);
			stat_date(p, &l, stp);
		}
		closedir(d);
		if (dirl) qsort(dir, dirl, sizeof(struct dirs), (int(*)(const void *, const void *))comp_de);
		for (i = 0; i < dirl; i++) {
			unsigned char *lnk = NULL;
#ifdef FS_UNIX_SOFTLINKS
			if (dir[i].s[0] == 'l') {
				unsigned char *buf = NULL;
				int size = 0;
				int r;
				unsigned char *n = stracpy(name);
				add_to_strn(&n, dir[i].f);
				do {
					if (buf) mem_free(buf);
					size += ALLOC_GR;
					if ((unsigned)size > MAXINT) overalloc();
					buf = mem_alloc(size);
					r = readlink(n, buf, size);
				} while (r == size);
				if (r == -1) goto yyy;
				buf[r] = 0;
				lnk = buf;
				goto xxx;
				yyy:
				mem_free(buf);
				xxx:
				mem_free(n);
			}
#endif
			/*add_to_str(&file, &fl, "   ");*/
			add_to_str(&file, &fl, dir[i].s);
			add_to_str(&file, &fl, "<a href=\"");
			add_conv_str(&file, &fl, dir[i].f, strlen(dir[i].f), 1);
			if (dir[i].s[0] == 'd') add_to_str(&file, &fl, "/");
			else if (lnk) {
				struct stat st;
				unsigned char *n = stracpy(name);
				add_to_strn(&n, dir[i].f);
				if (!stat(n, &st)) if (S_ISDIR(st.st_mode)) add_to_str(&file, &fl, "/");
				mem_free(n);
			}
			add_to_str(&file, &fl, "\">");
			/*if (dir[i].s[0] == 'd') add_to_str(&file, &fl, "<font color=\"yellow\">");*/
			add_conv_str(&file, &fl, dir[i].f, strlen(dir[i].f), 0);
			/*if (dir[i].s[0] == 'd') add_to_str(&file, &fl, "</font>");*/
			add_to_str(&file, &fl, "</a>");
			if (lnk) {
				add_to_str(&file, &fl, " -> ");
				add_to_str(&file, &fl, lnk);
				mem_free(lnk);
			}
			add_to_str(&file, &fl, "\n");
		}
		mem_free(name);
		for (i = 0; i < dirl; i++) mem_free(dir[i].s), mem_free(dir[i].f);
		mem_free(dir);
		add_to_str(&file, &fl, "</pre></body></html>\n");
		head = stracpy("\r\nContent-Type: text/html\r\n");
	} else {
		mem_free(name);
		/* + !stt.st_size is there because of bug in Linux. Read returns
		   -EACCES when reading 0 bytes to invalid address */
		if (stt.st_size > MAXINT) {
			close(h);
			setcstate(c, S_LARGE_FILE); abort_connection(c);
			return;
		}
		file = mem_alloc(stt.st_size + !stt.st_size);
		if ((r = read(h, file, stt.st_size)) != stt.st_size) {
			mem_free(file); close(h);
			setcstate(c, r == -1 ? -errno : S_FILE_ERROR);
			abort_connection(c); return;
		}
		close(h);
		fl = stt.st_size;
		head = stracpy("");
	}
	if (get_cache_entry(c->url, &e)) {
		mem_free(file);
		setcstate(c, S_OUT_OF_MEM); abort_connection(c); return;
	}
	if (e->head) mem_free(e->head);
	e->head = head;
	c->cache = e;
	add_fragment(e, 0, file, fl);
	truncate_entry(e, fl, 1);
	mem_free(file);
	end:
	c->cache->incomplete = 0;
	setcstate(c, S_OK);
	abort_connection(c);
}
コード例 #4
0
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(mqtt_process, ev, data)
{
  static struct mqtt_connection *conn;

  PROCESS_BEGIN();

  while(1) {
    PROCESS_WAIT_EVENT();

    if(ev == mqtt_abort_now_event) {
      DBG("MQTT - Abort\n");
      conn = data;
      conn->state = MQTT_CONN_STATE_ABORT_IMMEDIATE;

      abort_connection(conn);
    }
    if(ev == mqtt_do_connect_tcp_event) {
      conn = data;
      DBG("MQTT - Got mqtt_do_connect_tcp_event!\n");
      connect_tcp(conn);
    }
    if(ev == mqtt_do_connect_mqtt_event) {
      conn = data;
      conn->socket.output_data_max_seg = conn->max_segment_size;
      DBG("MQTT - Got mqtt_do_connect_mqtt_event!\n");

      if(conn->out_buffer_sent == 1) {
        PT_INIT(&conn->out_proto_thread);
        while(connect_pt(&conn->out_proto_thread, conn) < PT_EXITED &&
              conn->state != MQTT_CONN_STATE_ABORT_IMMEDIATE) {
          PT_MQTT_WAIT_SEND();
        }
      }
    }
    if(ev == mqtt_do_disconnect_mqtt_event) {
      conn = data;
      DBG("MQTT - Got mqtt_do_disconnect_mqtt_event!\n");

      /* Send MQTT Disconnect if we are connected */
      if(conn->state == MQTT_CONN_STATE_SENDING_MQTT_DISCONNECT) {
        if(conn->out_buffer_sent == 1) {
          PT_INIT(&conn->out_proto_thread);
          while(disconnect_pt(&conn->out_proto_thread, conn) < PT_EXITED &&
                conn->state != MQTT_CONN_STATE_ABORT_IMMEDIATE) {
            PT_MQTT_WAIT_SEND();
          }
          abort_connection(conn);
          call_event(conn, MQTT_EVENT_DISCONNECTED, &ev);
        } else {
          process_post(&mqtt_process, mqtt_do_disconnect_mqtt_event, conn);
        }
      }
    }
    if(ev == mqtt_do_pingreq_event) {
      conn = data;
      DBG("MQTT - Got mqtt_do_pingreq_event!\n");

      if(conn->out_buffer_sent == 1 &&
         conn->state == MQTT_CONN_STATE_CONNECTED_TO_BROKER) {
        PT_INIT(&conn->out_proto_thread);
        while(pingreq_pt(&conn->out_proto_thread, conn) < PT_EXITED &&
              conn->state == MQTT_CONN_STATE_CONNECTED_TO_BROKER) {
          PT_MQTT_WAIT_SEND();
        }
      }
    }
    if(ev == mqtt_do_subscribe_event) {
      conn = data;
      DBG("MQTT - Got mqtt_do_subscribe_mqtt_event!\n");

      if(conn->out_buffer_sent == 1 &&
         conn->state == MQTT_CONN_STATE_CONNECTED_TO_BROKER) {
        PT_INIT(&conn->out_proto_thread);
        while(subscribe_pt(&conn->out_proto_thread, conn) < PT_EXITED &&
              conn->state == MQTT_CONN_STATE_CONNECTED_TO_BROKER) {
          PT_MQTT_WAIT_SEND();
        }
      }
    }
    if(ev == mqtt_do_unsubscribe_event) {
      conn = data;
      DBG("MQTT - Got mqtt_do_unsubscribe_mqtt_event!\n");

      if(conn->out_buffer_sent == 1 &&
         conn->state == MQTT_CONN_STATE_CONNECTED_TO_BROKER) {
        PT_INIT(&conn->out_proto_thread);
        while(unsubscribe_pt(&conn->out_proto_thread, conn) < PT_EXITED &&
              conn->state == MQTT_CONN_STATE_CONNECTED_TO_BROKER) {
          PT_MQTT_WAIT_SEND();
        }
      }
    }
    if(ev == mqtt_do_publish_event) {
      conn = data;
      DBG("MQTT - Got mqtt_do_publish_mqtt_event!\n");

      if(conn->out_buffer_sent == 1 &&
         conn->state == MQTT_CONN_STATE_CONNECTED_TO_BROKER) {
        PT_INIT(&conn->out_proto_thread);
        while(publish_pt(&conn->out_proto_thread, conn) < PT_EXITED &&
              conn->state == MQTT_CONN_STATE_CONNECTED_TO_BROKER) {
          PT_MQTT_WAIT_SEND();
        }
      }
    }
  }
  PROCESS_END();
}
コード例 #5
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));
}
コード例 #6
0
ファイル: smb2.c プロジェクト: Efreak/elinks
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);
	}
}
コード例 #7
0
ファイル: smb2.c プロジェクト: Efreak/elinks
static void
smb_got_header(struct socket *socket, struct read_buffer *rb)
{
	struct connection *conn = socket->conn;
	struct read_buffer *buf;
	int error = 0;

	conn->cached = get_cache_entry(conn->uri);
	if (!conn->cached) {
		/* Even though these are pipes rather than real
		 * sockets, call close_socket instead of close, to
		 * ensure that abort_connection won't try to close the
		 * file descriptors again.  (Could we skip the calls
		 * and assume abort_connection will do them?)  */
		close_socket(socket);
		close_socket(conn->data_socket);
		abort_connection(conn, connection_state(S_OUT_OF_MEM));
		return;
	}
	socket->state = SOCKET_END_ONCLOSE;

	if (rb->length > 0) {
		unsigned char *ctype = memacpy(rb->data, rb->length);

		if (ctype && *ctype) {
			if (!strcmp(ctype, "text/x-error")) {
				error = 1;
				mem_free(ctype);
			} else {
				if (ctype[0] >= '0' && ctype[0] <= '9') {
#ifdef HAVE_ATOLL
					conn->est_length = (off_t)atoll(ctype);
#else
					conn->est_length = (off_t)atol(ctype);
#endif
					mem_free(ctype);

					/* avoid error */
					if (!conn->est_length) {
						abort_connection(conn, connection_state(S_OK));
						return;
					}
				}
				else mem_free_set(&conn->cached->content_type, ctype);
			}
		} else {
			mem_free_if(ctype);
		}
	}

	buf = alloc_read_buffer(conn->data_socket);
	if (!buf) {
		close_socket(socket);
		close_socket(conn->data_socket);
		abort_connection(conn, connection_state(S_OUT_OF_MEM));
		return;
	}
	if (error) {
		mem_free_set(&conn->cached->content_type, stracpy("text/html"));
		read_from_socket(conn->data_socket, buf,
				 connection_state(S_CONN), smb_got_error);
	} else {
		read_from_socket(conn->data_socket, buf,
				 connection_state(S_CONN), smb_got_data);
	}
}
コード例 #8
0
ファイル: smb2.c プロジェクト: Efreak/elinks
/* Kill the current connection and ask for a username/password for the next
 * try. */
static void
prompt_username_pw(struct connection *conn)
{
	add_auth_entry(conn->uri, "Samba", NULL, NULL, 0);
	abort_connection(conn, connection_state(S_OK));
}
コード例 #9
0
void https_func(struct connection *c)
{
	setcstate(c, S_NO_SSL);
	abort_connection(c);
}
コード例 #10
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);
}
コード例 #11
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);
}
コード例 #12
0
static struct ftp_connection_info *add_file_cmd_to_str(struct connection *c)
{
    unsigned char *d = get_url_data(c->url);
    unsigned char *de;
    int del;
    unsigned char port_string[50];
    struct ftp_connection_info *inf, *inf2;
    unsigned char *s;
    int l;
    if (!d) {
        internal("get_url_data failed");
        setcstate(c, S_INTERNAL);
        abort_connection(c);
        return NULL;
    }

    de = init_str(), del = 0;
    add_conv_str(&de, &del, d, strlen(cast_const_char d), -2);
    d = de;
    inf = mem_alloc(sizeof(struct ftp_connection_info));
    memset(inf, 0, sizeof(struct ftp_connection_info));
    l = 0;
    s = init_str();
    inf->pasv = ftp_options.passive_ftp;
#ifdef LINKS_2
    if (*c->socks_proxy) inf->pasv = 1;
    if (ftp_options.eprt_epsv || is_ipv6(c->sock1)) inf->eprt_epsv = 1;
#endif
    c->info = inf;

    if (!inf->pasv) {
        int ps;
#ifdef SUPPORT_IPV6
        if (is_ipv6(c->sock1)) {
            ps = get_pasv_socket_ipv6(c, c->sock1, &c->sock2, port_string);
            if (ps) {
                mem_free(d);
                mem_free(s);
                return NULL;
            }
        } else
#endif
        {
            unsigned char pc[6];
            ps = get_pasv_socket(c, c->sock1, &c->sock2, pc);
            if (ps) {
                mem_free(d);
                mem_free(s);
                return NULL;
            }
            if (inf->eprt_epsv)
                sprintf(cast_char port_string, "|1|%d.%d.%d.%d|%d|", pc[0], pc[1], pc[2], pc[3], (pc[4] << 8) | pc[5]);
            else
                sprintf(cast_char port_string, "%d,%d,%d,%d,%d,%d", pc[0], pc[1], pc[2], pc[3], pc[4], pc[5]);
        }
        if (strlen(cast_const_char port_string) >= sizeof(port_string))
            internal("buffer overflow in get_pasv_socket_ipv6: %d > %d", (int)strlen(cast_const_char port_string), (int)sizeof(port_string));
    }
#ifdef HAVE_IPTOS
    if (ftp_options.set_tos) {
        int rx;
        int on = IPTOS_THROUGHPUT;
        EINTRLOOP(rx, setsockopt(c->sock2, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)));
    }
#endif
    if (!(de = cast_uchar strchr(cast_const_char d, POST_CHAR))) de = d + strlen(cast_const_char d);
    if (d == de || de[-1] == '/') {
        inf->dir = 1;
        inf->pending_commands = 4;
        add_to_str(&s, &l, cast_uchar "TYPE A\r\n");
        add_port_pasv(&s, &l, inf, port_string);
        add_to_str(&s, &l, cast_uchar "CWD /");
        add_bytes_to_str(&s, &l, d, de - d);
        add_to_str(&s, &l, cast_uchar "\r\nLIST\r\n");
        c->from = 0;
    } else {
        inf->dir = 0;
        inf->pending_commands = 3;
        add_to_str(&s, &l, cast_uchar "TYPE I\r\n");
        add_port_pasv(&s, &l, inf, port_string);
        if (c->from && c->no_cache < NC_IF_MOD) {
            add_to_str(&s, &l, cast_uchar "REST ");
            add_num_to_str(&s, &l, c->from);
            add_to_str(&s, &l, cast_uchar "\r\n");
            inf->rest_sent = 1;
            inf->pending_commands++;
        } else c->from = 0;
        add_to_str(&s, &l, cast_uchar "RETR /");
        add_bytes_to_str(&s, &l, d, de - d);
        add_to_str(&s, &l, cast_uchar "\r\n");
    }
    inf->opc = inf->pending_commands;
    if ((unsigned)l > MAXINT - sizeof(struct ftp_connection_info) - 1) overalloc();
    inf2 = mem_realloc(inf, sizeof(struct ftp_connection_info) + l + 1);
    strcpy(cast_char (inf = inf2)->cmdbuf, cast_const_char s);
    mem_free(s);
    c->info = inf;
    mem_free(d);
    return inf;
}
コード例 #13
0
ファイル: file.c プロジェクト: rkd77/elinks-tv
/* To reduce redundant error handling code [calls to abort_connection()]
 * most of the function is build around conditions that will assign the error
 * code to @state if anything goes wrong. The rest of the function will then just
 * do the necessary cleanups. If all works out we end up with @state being S_OK
 * resulting in a cache entry being created with the fragment data generated by
 * either reading the file content or listing a directory. */
void
file_protocol_handler(struct connection *connection)
{
	unsigned char *redirect_location = NULL;
	struct string page, name;
	struct connection_state state;
	int set_dir_content_type = 0;

	if (get_cmd_opt_bool((const unsigned char *)"anonymous")) {
		if (strcmp((const char *)connection->uri->string, "file:///dev/stdin")
		    || isatty(STDIN_FILENO)) {
			abort_connection(connection,
					 connection_state(S_FILE_ANONYMOUS));
			return;
		}
	}

#ifdef CONFIG_CGI
	if (!execute_cgi(connection)) return;
#endif /* CONFIG_CGI */

	/* Treat /dev/stdin in special way */
	if (!strcmp((const char *)connection->uri->string, "file:///dev/stdin")) {
		int fd = open("/dev/stdin", O_RDONLY);

		if (fd == -1) {
			abort_connection(connection, connection_state(-errno));
			return;
		}
		set_nonblocking_fd(fd);
		if (!init_http_connection_info(connection, 1, 0, 1)) {
			abort_connection(connection, connection_state(S_OUT_OF_MEM));
			close(fd);
			return;
		}
		connection->socket->fd = fd;
		connection->data_socket->fd = -1;
		read_from_stdin(connection);
		return;
	}


	/* This function works on already simplified file-scheme URI pre-chewed
	 * by transform_file_url(). By now, the function contains no hostname
	 * part anymore, possibly relative path is converted to an absolute one
	 * and uri->data is just the final path to file/dir we should try to
	 * show. */

	if (!init_string(&name)
	    || !add_uri_to_string(&name, connection->uri, URI_PATH)) {
		done_string(&name);
		abort_connection(connection, connection_state(S_OUT_OF_MEM));
		return;
	}

	decode_uri_string(&name);

	/* In Win32, file_is_dir seems to always return 0 if the name
	 * ends with a directory separator.  */
	if ((name.length > 0 && dir_sep(name.source[name.length - 1]))
	    || file_is_dir(name.source)) {
		/* In order for global history and directory listing to
		 * function properly the directory url must end with a
		 * directory separator. */
		if (name.source[0] && !dir_sep(name.source[name.length - 1])) {
			redirect_location = (unsigned char *)STRING_DIR_SEP;
			state = connection_state(S_OK);
		} else {
			state = list_directory(connection, name.source, &page);
			set_dir_content_type = 1;
		}

	} else {
		state = read_encoded_file(&name, &page);
		/* FIXME: If state is now S_ENCODE_ERROR we should try loading
		 * the file undecoded. --jonas */
	}

	done_string(&name);

	if (is_in_state(state, S_OK)) {
		struct cache_entry *cached;

		/* Try to add fragment data to the connection cache if either
		 * file reading or directory listing worked out ok. */
		cached = connection->cached = get_cache_entry(connection->uri);
		if (!connection->cached) {
			if (!redirect_location) done_string(&page);
			state = connection_state(S_OUT_OF_MEM);

		} else if (redirect_location) {
			if (!redirect_cache(cached, redirect_location, 1, 0))
				state = connection_state(S_OUT_OF_MEM);

		} else {
			add_fragment(cached, 0, page.source, page.length);
			connection->from += page.length;

			if (!cached->head && set_dir_content_type) {
				unsigned char *head;

				/* If the system charset somehow
				 * changes after the directory listing
				 * has been generated, it should be
				 * parsed with the original charset.  */
				head = straconcat((const unsigned char *)"\r\nContent-Type: text/html; charset=",
						  get_cp_mime_name(get_cp_index((const unsigned char *)"System")),
						  "\r\n", (unsigned char *) NULL);

				/* Not so gracefully handle failed memory
				 * allocation. */
				if (!head)
					state = connection_state(S_OUT_OF_MEM);

				/* Setup directory listing for viewing. */
				mem_free_set(&cached->head, head);
			}

			done_string(&page);
		}
	}

	abort_connection(connection, state);
}
コード例 #14
0
struct ftp_connection_info *add_file_cmd_to_str(struct connection *c)
{
	unsigned char *d = get_url_data(c->url);
	unsigned char *de;
	int del;
	unsigned char pc[6];
	int ps;
	struct ftp_connection_info *inf, *inf2;
	unsigned char *s;
	int l;
	if (!d) {
		internal("get_url_data failed");
		setcstate(c, S_INTERNAL);
		abort_connection(c);
		return NULL;
	}
	de = init_str(), del = 0;
	add_conv_str(&de, &del, d, strlen(d), -2);
	d = de;
	inf = mem_alloc(sizeof(struct ftp_connection_info));
	memset(inf, 0, sizeof(struct ftp_connection_info));
	l = 0;
	s = init_str();
	inf->pasv = ftp_options.passive_ftp;
	if (*c->socks_proxy) inf->pasv = 1;
	c->info = inf;
	if (!inf->pasv) if ((ps = get_pasv_socket(c, c->sock1, &c->sock2, pc))) {
		mem_free(d);
		return NULL;
	}
#ifdef HAVE_IPTOS
	if (ftp_options.set_tos) {
		int on = IPTOS_THROUGHPUT;
		setsockopt(c->sock2, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int));
	}
#endif
	if (!(de = strchr(d, POST_CHAR))) de = d + strlen(d);
	if (d == de || de[-1] == '/') {
		inf->dir = 1;
		inf->pending_commands = 4;
		add_to_str(&s, &l, "TYPE A\r\n");
		if (!inf->pasv) {
			add_to_str(&s, &l, "PORT ");
			add_num_to_str(&s, &l, pc[0]);
			add_chr_to_str(&s, &l, ',');
			add_num_to_str(&s, &l, pc[1]);
			add_chr_to_str(&s, &l, ',');
			add_num_to_str(&s, &l, pc[2]);
			add_chr_to_str(&s, &l, ',');
			add_num_to_str(&s, &l, pc[3]);
			add_chr_to_str(&s, &l, ',');
			add_num_to_str(&s, &l, pc[4]);
			add_chr_to_str(&s, &l, ',');
			add_num_to_str(&s, &l, pc[5]);
			add_to_str(&s, &l, "\r\n");
		} else {
			add_to_str(&s, &l, "PASV\r\n");
		}
		add_to_str(&s, &l, "CWD /");
		add_bytes_to_str(&s, &l, d, de - d);
		add_to_str(&s, &l, "\r\nLIST\r\n");
		c->from = 0;
	} else {
		inf->dir = 0;
		inf->pending_commands = 3;
		add_to_str(&s, &l, "TYPE I\r\n");
		if (!inf->pasv) {
			add_to_str(&s, &l, "PORT ");
			add_num_to_str(&s, &l, pc[0]);
			add_chr_to_str(&s, &l, ',');
			add_num_to_str(&s, &l, pc[1]);
			add_chr_to_str(&s, &l, ',');
			add_num_to_str(&s, &l, pc[2]);
			add_chr_to_str(&s, &l, ',');
			add_num_to_str(&s, &l, pc[3]);
			add_chr_to_str(&s, &l, ',');
			add_num_to_str(&s, &l, pc[4]);
			add_chr_to_str(&s, &l, ',');
			add_num_to_str(&s, &l, pc[5]);
			add_to_str(&s, &l, "\r\n");
		} else {
			add_to_str(&s, &l, "PASV\r\n");
		}
		if (c->from && c->no_cache < NC_IF_MOD) {
			add_to_str(&s, &l, "REST ");
			add_num_to_str(&s, &l, c->from);
			add_to_str(&s, &l, "\r\n");
			inf->rest_sent = 1;
			inf->pending_commands++;
		} else c->from = 0;
		add_to_str(&s, &l, "RETR /");
		add_bytes_to_str(&s, &l, d, de - d);
		add_to_str(&s, &l, "\r\n");
	}
	inf->opc = inf->pending_commands;
	if ((unsigned)l > MAXINT - sizeof(struct ftp_connection_info) - 1) overalloc();
	inf2 = mem_realloc(inf, sizeof(struct ftp_connection_info) + l + 1);
	strcpy((inf = inf2)->cmdbuf, s);
	mem_free(s);
	c->info = inf;
	mem_free(d);
	return inf;
}