X-Git-Url: http://git.archive.openwrt.org/?p=project%2Fuclient.git;a=blobdiff_plain;f=uclient-http.c;h=ebe77582368ebee4f7a50482f49b154b12371b16;hp=f0451cc805b7c65eb70553616198838935ee3570;hb=HEAD;hpb=53e2fb59bde914bcded2618d0ce6ce4df267b4a4 diff --git a/uclient-http.c b/uclient-http.c index f0451cc..ebe7758 100644 --- a/uclient-http.c +++ b/uclient-http.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -298,7 +299,7 @@ static bool uclient_request_supports_body(enum request_type req_type) } } -static void +static int uclient_http_add_auth_basic(struct uclient_http *uh) { struct uclient_url *url = uh->uc.url; @@ -306,11 +307,16 @@ uclient_http_add_auth_basic(struct uclient_http *uh) char *auth_buf; if (auth_len > 512) - return; + return -EINVAL; auth_buf = alloca(base64_len(auth_len) + 1); + if (!auth_buf) + return -ENOMEM; + base64_encode(url->auth, auth_len, auth_buf); ustream_printf(uh->us, "Authorization: Basic %s\r\n", auth_buf); + + return 0; } static char *digest_unquote_sep(char **str) @@ -379,11 +385,14 @@ get_cnonce(char *dest) { uint32_t val = 0; FILE *f; + size_t n; f = fopen("/dev/urandom", "r"); if (f) { - fread(&val, sizeof(val), 1, f); + n = fread(&val, sizeof(val), 1, f); fclose(f); + if (n != 1) + return; } bin_to_hex(dest, &val, sizeof(val)); @@ -424,14 +433,15 @@ static void add_field(char **buf, int *ofs, int *len, const char *name, const ch *ofs = cur - *buf; } -static void +static int uclient_http_add_auth_digest(struct uclient_http *uh) { struct uclient_url *url = uh->uc.url; const char *realm = NULL, *opaque = NULL; const char *user, *password; - char *buf, *next; + char *buf, *next, *buf_orig; int len, ofs; + int err = 0; char cnonce_str[9]; char nc_str[9]; @@ -445,14 +455,21 @@ uclient_http_add_auth_digest(struct uclient_http *uh) }; len = strlen(uh->auth_str) + 1; - if (len > 512) - return; + if (len > 512) { + err = -EINVAL; + goto fail; + } buf = alloca(len); + if (!buf) { + err = -ENOMEM; + goto fail; + } + strcpy(buf, uh->auth_str); /* skip auth type */ - strsep(&buf, " "); + buf_orig = strsep(&buf, " "); next = buf; while (*next) { @@ -486,8 +503,10 @@ uclient_http_add_auth_digest(struct uclient_http *uh) *dest = digest_unquote_sep(&next); } - if (!realm || !data.qop || !data.nonce) - return; + if (!realm || !data.qop || !data.nonce) { + err = -EINVAL; + goto fail_buf; + } sprintf(nc_str, "%08x", uh->nc++); get_cnonce(cnonce_str); @@ -501,10 +520,17 @@ uclient_http_add_auth_digest(struct uclient_http *uh) char *user_buf; len = password - url->auth; - if (len > 256) - return; + if (len > 256) { + err = -EINVAL; + goto fail_buf; + } user_buf = alloca(len + 1); + if (!user_buf) { + err = -ENOMEM; + goto fail_buf; + } + strncpy(user_buf, url->auth, len); user_buf[len] = 0; user = user_buf; @@ -531,47 +557,62 @@ uclient_http_add_auth_digest(struct uclient_http *uh) add_field(&buf, &ofs, &len, "opaque", opaque); ustream_printf(uh->us, "Authorization: Digest nc=%s, qop=%s%s\r\n", data.nc, data.qop, buf); + free(buf); + + return 0; + +fail_buf: + free(buf_orig); +fail: + return err; } -static void +static int uclient_http_add_auth_header(struct uclient_http *uh) { if (!uh->uc.url->auth) - return; + return 0; switch (uh->auth_type) { case AUTH_TYPE_UNKNOWN: case AUTH_TYPE_NONE: break; case AUTH_TYPE_BASIC: - uclient_http_add_auth_basic(uh); - break; + return uclient_http_add_auth_basic(uh); case AUTH_TYPE_DIGEST: - uclient_http_add_auth_digest(uh); - break; + return uclient_http_add_auth_digest(uh); } + + return 0; } -static void +static int uclient_http_send_headers(struct uclient_http *uh) { struct uclient_url *url = uh->uc.url; struct blob_attr *cur; enum request_type req_type = uh->req_type; - int rem; + bool literal_ipv6; + int err, rem; if (uh->state >= HTTP_STATE_HEADERS_SENT) - return; + return 0; if (uh->uc.proxy_url) url = uh->uc.proxy_url; + literal_ipv6 = strchr(url->host, ':'); + ustream_printf(uh->us, "%s %s HTTP/1.1\r\n" - "Host: %s\r\n", - request_types[req_type], - url->location, url->host); + "Host: %s%s%s%s%s\r\n", + request_types[req_type], url->location, + literal_ipv6 ? "[" : "", + url->host, + literal_ipv6 ? "]" : "", + url->port ? ":" : "", + url->port ? url->port : ""); blobmsg_for_each_attr(cur, uh->headers.head, rem) ustream_printf(uh->us, "%s: %s\r\n", blobmsg_name(cur), (char *) blobmsg_data(cur)); @@ -579,11 +620,15 @@ uclient_http_send_headers(struct uclient_http *uh) if (uclient_request_supports_body(uh->req_type)) ustream_printf(uh->us, "Transfer-Encoding: chunked\r\n"); - uclient_http_add_auth_header(uh); + err = uclient_http_add_auth_header(uh); + if (err) + return err; ustream_printf(uh->us, "\r\n"); uh->state = HTTP_STATE_HEADERS_SENT; + + return 0; } static void uclient_http_headers_complete(struct uclient_http *uh) @@ -905,6 +950,9 @@ static struct uclient *uclient_http_alloc(void) struct uclient_http *uh; uh = calloc_a(sizeof(*uh)); + if (!uh) + return NULL; + uh->disconnect_t.cb = uclient_http_disconnect_cb; blob_buf_init(&uh->headers, 0); @@ -980,11 +1028,14 @@ static int uclient_http_send_data(struct uclient *cl, const char *buf, unsigned int len) { struct uclient_http *uh = container_of(cl, struct uclient_http, uc); + int err; if (uh->state >= HTTP_STATE_REQUEST_DONE) return -1; - uclient_http_send_headers(uh); + err = uclient_http_send_headers(uh); + if (err) + return err; if (len > 0) { ustream_printf(uh->us, "%X\r\n", len); @@ -999,11 +1050,15 @@ static int uclient_http_request_done(struct uclient *cl) { struct uclient_http *uh = container_of(cl, struct uclient_http, uc); + int err; if (uh->state >= HTTP_STATE_REQUEST_DONE) return -1; - uclient_http_send_headers(uh); + err = uclient_http_send_headers(uh); + if (err) + return err; + if (uclient_request_supports_body(uh->req_type)) ustream_printf(uh->us, "0\r\n\r\n"); uh->state = HTTP_STATE_REQUEST_DONE; @@ -1114,7 +1169,7 @@ int uclient_http_redirect(struct uclient *cl) if (!tb) return false; - url = uclient_get_url(blobmsg_data(tb), url->auth); + url = uclient_get_url_location(url, blobmsg_data(tb)); if (!url) return false;