Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : HTTP library
5 :
6 : Copyright (C) 2013 Samuel Cabrero <samuelcabrero@kernevil.me>
7 :
8 : This program is free software; you can redistribute it and/or modify
9 : it under the terms of the GNU General Public License as published by
10 : the Free Software Foundation; either version 3 of the License, or
11 : (at your option) any later version.
12 :
13 : This program is distributed in the hope that it will be useful,
14 : but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : GNU General Public License for more details.
17 :
18 : You should have received a copy of the GNU General Public License
19 : along with this program. If not, see <http://www.gnu.org/licenses/>.
20 : */
21 :
22 : #include "includes.h"
23 : #include "lib/util/tevent_ntstatus.h"
24 : #include "http.h"
25 : #include "http_internal.h"
26 : #include "util/tevent_werror.h"
27 : #include "lib/util/dlinklist.h"
28 :
29 : #undef strcasecmp
30 :
31 : enum http_body_type {
32 : BODY_NONE = 0,
33 : BODY_CONTENT_LENGTH,
34 : BODY_CHUNKED,
35 : BODY_ERROR = -1
36 : };
37 :
38 : /**
39 : * Determines if a response should have a body.
40 : * @return 2 if response MUST use chunked encoding,
41 : * 1 if the response MUST have a body;
42 : * 0 if the response MUST NOT have a body.
43 : * Returns -1 on error.
44 : */
45 20 : static enum http_body_type http_response_needs_body(
46 : struct http_request *req)
47 : {
48 20 : struct http_header *h = NULL;
49 :
50 20 : if (!req) {
51 0 : return BODY_ERROR;
52 : }
53 :
54 80 : for (h = req->headers; h != NULL; h = h->next) {
55 0 : int cmp;
56 0 : int n;
57 0 : char c;
58 0 : unsigned long long v;
59 :
60 80 : cmp = strcasecmp(h->key, "Transfer-Encoding");
61 80 : if (cmp == 0) {
62 10 : cmp = strcasecmp(h->value, "chunked");
63 10 : if (cmp == 0) {
64 20 : return BODY_CHUNKED;
65 : }
66 : /* unsupported Transfer-Encoding type */
67 2 : DBG_ERR("Unsupported transfer encoding type %s\n",
68 : h->value);
69 2 : return BODY_ERROR;
70 : }
71 :
72 70 : cmp = strcasecmp(h->key, "Content-Length");
73 70 : if (cmp != 0) {
74 60 : continue;
75 : }
76 :
77 10 : n = sscanf(h->value, "%llu%c", &v, &c);
78 10 : if (n != 1) {
79 0 : return BODY_ERROR;
80 : }
81 :
82 10 : req->remaining_content_length = v;
83 :
84 10 : if (v != 0) {
85 10 : return BODY_CONTENT_LENGTH;
86 : }
87 :
88 0 : return BODY_NONE;
89 : }
90 :
91 0 : return BODY_NONE;
92 : }
93 : struct http_chunk
94 : {
95 : struct http_chunk *prev, *next;
96 : DATA_BLOB blob;
97 : };
98 :
99 : struct http_read_response_state {
100 : enum http_parser_state parser_state;
101 : size_t max_headers_size;
102 : uint64_t max_content_length;
103 : DATA_BLOB buffer;
104 : struct http_request *response;
105 : struct http_chunk *chunks;
106 : };
107 :
108 : /**
109 : * Parses the HTTP headers
110 : */
111 2938 : static enum http_read_status http_parse_headers(struct http_read_response_state *state)
112 : {
113 2938 : enum http_read_status status = HTTP_ALL_DATA_READ;
114 2938 : char *ptr = NULL;
115 2938 : char *line = NULL;
116 2938 : char *key = NULL;
117 2938 : char *value = NULL;
118 2938 : int n = 0;
119 0 : enum http_body_type ret;
120 :
121 : /* Sanity checks */
122 2938 : if (!state || !state->response) {
123 0 : DEBUG(0, ("%s: Invalid Parameter\n", __func__));
124 0 : return HTTP_DATA_CORRUPTED;
125 : }
126 :
127 2938 : if (state->buffer.length > state->max_headers_size) {
128 0 : DEBUG(0, ("%s: Headers too long: %zi, maximum length is %zi\n", __func__,
129 : state->buffer.length, state->max_headers_size));
130 0 : return HTTP_DATA_TOO_LONG;
131 : }
132 :
133 2938 : line = talloc_strndup(state, (char *)state->buffer.data, state->buffer.length);
134 2938 : if (!line) {
135 0 : DEBUG(0, ("%s: Memory error\n", __func__));
136 0 : return HTTP_DATA_CORRUPTED;
137 : }
138 :
139 2938 : ptr = strstr(line, "\r\n");
140 2938 : if (ptr == NULL) {
141 2838 : TALLOC_FREE(line);
142 2838 : return HTTP_MORE_DATA_EXPECTED;
143 : }
144 :
145 100 : state->response->headers_size += state->buffer.length;
146 :
147 100 : if (strncmp(line, "\r\n", 2) == 0) {
148 20 : DEBUG(11,("%s: All headers read\n", __func__));
149 :
150 20 : ret = http_response_needs_body(state->response);
151 20 : switch (ret) {
152 8 : case BODY_CHUNKED:
153 8 : DEBUG(11, ("%s: need to process chunks... %d\n", __func__,
154 : state->response->response_code));
155 8 : state->parser_state = HTTP_READING_CHUNK_SIZE;
156 8 : break;
157 10 : case BODY_CONTENT_LENGTH:
158 10 : if (state->response->remaining_content_length <= state->max_content_length) {
159 8 : DEBUG(11, ("%s: Start of read body\n", __func__));
160 8 : state->parser_state = HTTP_READING_BODY;
161 8 : break;
162 : }
163 0 : FALL_THROUGH;
164 : case BODY_NONE:
165 2 : DEBUG(11, ("%s: Skipping body for code %d\n", __func__,
166 : state->response->response_code));
167 2 : state->parser_state = HTTP_READING_DONE;
168 2 : break;
169 2 : case BODY_ERROR:
170 2 : DEBUG(0, ("%s_: Error in http_response_needs_body\n", __func__));
171 2 : TALLOC_FREE(line);
172 2 : return HTTP_DATA_CORRUPTED;
173 0 : break;
174 : }
175 :
176 18 : TALLOC_FREE(line);
177 18 : return HTTP_ALL_DATA_READ;
178 : }
179 :
180 80 : n = sscanf(line, "%m[^:]: %m[^\r\n]\r\n", &key, &value);
181 80 : if (n != 2) {
182 0 : DEBUG(0, ("%s: Error parsing header '%s'\n", __func__, line));
183 0 : status = HTTP_DATA_CORRUPTED;
184 0 : goto error;
185 : }
186 :
187 80 : if (http_add_header(state->response, &state->response->headers, key, value) == -1) {
188 0 : DEBUG(0, ("%s: Error adding header\n", __func__));
189 0 : status = HTTP_DATA_CORRUPTED;
190 0 : goto error;
191 : }
192 :
193 80 : error:
194 80 : free(key);
195 80 : free(value);
196 80 : TALLOC_FREE(line);
197 80 : return status;
198 : }
199 :
200 6 : static bool http_response_process_chunks(struct http_read_response_state *state)
201 : {
202 6 : struct http_chunk *chunk = NULL;
203 6 : struct http_request *resp = state->response;
204 :
205 28 : for (chunk = state->chunks; chunk; chunk = chunk->next) {
206 22 : DBG_DEBUG("processing chunk of size %zi\n",
207 : chunk->blob.length);
208 22 : if (resp->body.data == NULL) {
209 6 : resp->body = chunk->blob;
210 6 : chunk->blob = data_blob_null;
211 6 : talloc_steal(resp, resp->body.data);
212 6 : continue;
213 : }
214 :
215 16 : resp->body.data =
216 16 : talloc_realloc(resp,
217 : resp->body.data,
218 : uint8_t,
219 : resp->body.length + chunk->blob.length);
220 16 : if (!resp->body.data) {
221 0 : return false;
222 : }
223 16 : memcpy(resp->body.data + resp->body.length,
224 16 : chunk->blob.data,
225 : chunk->blob.length);
226 :
227 16 : resp->body.length += chunk->blob.length;
228 :
229 16 : TALLOC_FREE(chunk->blob.data);
230 16 : chunk->blob = data_blob_null;
231 : }
232 6 : return true;
233 : }
234 :
235 72 : static enum http_read_status http_read_chunk_term(struct http_read_response_state *state)
236 : {
237 72 : enum http_read_status status = HTTP_ALL_DATA_READ;
238 72 : char *ptr = NULL;
239 72 : char *line = NULL;
240 :
241 : /* Sanity checks */
242 72 : if (!state || !state->response) {
243 0 : DBG_ERR("%s: Invalid Parameter\n", __func__);
244 0 : return HTTP_DATA_CORRUPTED;
245 : }
246 :
247 72 : line = talloc_strndup(state, (char *)state->buffer.data, state->buffer.length);
248 72 : if (!line) {
249 0 : DBG_ERR("%s: Memory error\n", __func__);
250 0 : return HTTP_DATA_CORRUPTED;
251 : }
252 72 : ptr = strstr(line, "\r\n");
253 72 : if (ptr == NULL) {
254 36 : TALLOC_FREE(line);
255 36 : return HTTP_MORE_DATA_EXPECTED;
256 : }
257 :
258 36 : if (strncmp(line, "\r\n", 2) == 0) {
259 : /* chunk terminator */
260 36 : if (state->parser_state == HTTP_READING_FINAL_CHUNK_TERM) {
261 6 : if (http_response_process_chunks(state) == false) {
262 0 : status = HTTP_DATA_CORRUPTED;
263 0 : goto out;
264 : }
265 6 : state->parser_state = HTTP_READING_DONE;
266 : } else {
267 30 : state->parser_state = HTTP_READING_CHUNK_SIZE;
268 : }
269 36 : status = HTTP_ALL_DATA_READ;
270 36 : goto out;
271 : }
272 :
273 0 : status = HTTP_DATA_CORRUPTED;
274 36 : out:
275 36 : TALLOC_FREE(line);
276 36 : return status;
277 : }
278 :
279 114 : static enum http_read_status http_read_chunk_size(struct http_read_response_state *state)
280 : {
281 114 : enum http_read_status status = HTTP_ALL_DATA_READ;
282 114 : char *ptr = NULL;
283 114 : char *line = NULL;
284 114 : char *value = NULL;
285 114 : int n = 0;
286 0 : unsigned long long v;
287 :
288 : /* Sanity checks */
289 114 : if (!state || !state->response) {
290 0 : DBG_ERR("%s: Invalid Parameter\n", __func__);
291 0 : return HTTP_DATA_CORRUPTED;
292 : }
293 :
294 114 : line = talloc_strndup(state, (char *)state->buffer.data, state->buffer.length);
295 114 : if (!line) {
296 0 : DBG_ERR("%s: Memory error\n", __func__);
297 0 : return HTTP_DATA_CORRUPTED;
298 : }
299 114 : ptr = strstr(line, "\r\n");
300 114 : if (ptr == NULL) {
301 76 : TALLOC_FREE(line);
302 76 : return HTTP_MORE_DATA_EXPECTED;
303 : }
304 :
305 38 : n = sscanf(line, "%m[^\r\n]\r\n", &value);
306 38 : if (n != 1) {
307 0 : DBG_ERR("%s: Error parsing chunk size '%s'\n", __func__, line);
308 0 : status = HTTP_DATA_CORRUPTED;
309 0 : goto out;
310 : }
311 :
312 38 : DBG_DEBUG("Got chunk size string %s\n", value);
313 38 : n = sscanf(value, "%llx", &v);
314 38 : if (n != 1) {
315 0 : DBG_ERR("%s: Error parsing chunk size '%s'\n", __func__, line);
316 0 : status = HTTP_DATA_CORRUPTED;
317 0 : goto out;
318 : }
319 38 : DBG_DEBUG("Got chunk size %llu 0x%llx\n", v, v);
320 38 : if (v == 0) {
321 6 : state->parser_state = HTTP_READING_FINAL_CHUNK_TERM;
322 : } else {
323 32 : state->parser_state = HTTP_READING_CHUNK;
324 : }
325 38 : state->response->remaining_content_length = v;
326 38 : status = HTTP_ALL_DATA_READ;
327 38 : out:
328 38 : if (value) {
329 38 : free(value);
330 : }
331 38 : TALLOC_FREE(line);
332 38 : return status;
333 : }
334 :
335 : /**
336 : * Parses the first line of a HTTP response
337 : */
338 20 : static bool http_parse_response_line(struct http_read_response_state *state)
339 : {
340 20 : bool status = true;
341 0 : char *protocol;
342 20 : char *msg = NULL;
343 0 : char major;
344 0 : char minor;
345 0 : int code;
346 20 : char *line = NULL;
347 0 : int n;
348 :
349 : /* Sanity checks */
350 20 : if (!state) {
351 0 : DEBUG(0, ("%s: Input parameter is NULL\n", __func__));
352 0 : return false;
353 : }
354 :
355 20 : line = talloc_strndup(state, (char*)state->buffer.data, state->buffer.length);
356 20 : if (!line) {
357 0 : DEBUG(0, ("%s: Memory error\n", __func__));
358 0 : return false;
359 : }
360 :
361 20 : n = sscanf(line, "%m[^/]/%c.%c %d %m[^\r\n]\r\n",
362 : &protocol, &major, &minor, &code, &msg);
363 :
364 20 : DEBUG(11, ("%s: Header parsed(%i): protocol->%s, major->%c, minor->%c, "
365 : "code->%d, message->%s\n", __func__, n, protocol, major, minor,
366 : code, msg));
367 :
368 20 : if (n != 5) {
369 0 : DEBUG(0, ("%s: Error parsing header\n", __func__));
370 0 : status = false;
371 0 : goto error;
372 : }
373 :
374 20 : if (major != '1') {
375 0 : DEBUG(0, ("%s: Bad HTTP major number '%c'\n", __func__, major));
376 0 : status = false;
377 0 : goto error;
378 : }
379 :
380 20 : if (code == 0) {
381 0 : DEBUG(0, ("%s: Bad response code '%d'\n", __func__, code));
382 0 : status = false;
383 0 : goto error;
384 : }
385 :
386 20 : if (msg == NULL) {
387 0 : DEBUG(0, ("%s: Error parsing HTTP data\n", __func__));
388 0 : status = false;
389 0 : goto error;
390 : }
391 :
392 20 : state->response->major = major;
393 20 : state->response->minor = minor;
394 20 : state->response->response_code = code;
395 20 : state->response->response_code_line = talloc_strndup(state->response,
396 : msg, strlen(msg));
397 :
398 20 : error:
399 20 : free(protocol);
400 20 : free(msg);
401 20 : TALLOC_FREE(line);
402 20 : return status;
403 : }
404 :
405 : /*
406 : * Parses header lines from a request or a response into the specified
407 : * request object given a buffer.
408 : *
409 : * Returns
410 : * HTTP_DATA_CORRUPTED on error
411 : * HTTP_MORE_DATA_EXPECTED when we need to read more headers
412 : * HTTP_DATA_TOO_LONG on error
413 : * HTTP_ALL_DATA_READ when all headers have been read
414 : */
415 340 : static enum http_read_status http_parse_firstline(struct http_read_response_state *state)
416 : {
417 340 : enum http_read_status status = HTTP_ALL_DATA_READ;
418 340 : char *ptr = NULL;
419 0 : char *line;
420 :
421 : /* Sanity checks */
422 340 : if (!state) {
423 0 : DEBUG(0, ("%s: Invalid Parameter\n", __func__));
424 0 : return HTTP_DATA_CORRUPTED;
425 : }
426 :
427 340 : if (state->buffer.length > state->max_headers_size) {
428 0 : DEBUG(0, ("%s: Headers too long: %zi, maximum length is %zi\n", __func__,
429 : state->buffer.length, state->max_headers_size));
430 0 : return HTTP_DATA_TOO_LONG;
431 : }
432 :
433 340 : line = talloc_strndup(state, (char *)state->buffer.data, state->buffer.length);
434 340 : if (!line) {
435 0 : DEBUG(0, ("%s: Not enough memory\n", __func__));
436 0 : return HTTP_DATA_CORRUPTED;
437 : }
438 :
439 340 : ptr = strstr(line, "\r\n");
440 340 : if (ptr == NULL) {
441 320 : TALLOC_FREE(line);
442 320 : return HTTP_MORE_DATA_EXPECTED;
443 : }
444 :
445 20 : state->response->headers_size = state->buffer.length;
446 20 : if (!http_parse_response_line(state)) {
447 0 : status = HTTP_DATA_CORRUPTED;
448 : }
449 :
450 : /* Next state, read HTTP headers */
451 20 : state->parser_state = HTTP_READING_HEADERS;
452 :
453 20 : TALLOC_FREE(line);
454 20 : return status;
455 : }
456 :
457 16 : static enum http_read_status http_read_body(struct http_read_response_state *state)
458 : {
459 16 : struct http_request *resp = state->response;
460 :
461 16 : if (state->buffer.length < resp->remaining_content_length) {
462 8 : return HTTP_MORE_DATA_EXPECTED;
463 : }
464 :
465 8 : resp->body = state->buffer;
466 8 : state->buffer = data_blob_null;
467 8 : talloc_steal(resp, resp->body.data);
468 8 : resp->remaining_content_length = 0;
469 :
470 8 : state->parser_state = HTTP_READING_DONE;
471 8 : return HTTP_ALL_DATA_READ;
472 : }
473 :
474 64 : static enum http_read_status http_read_chunk(struct http_read_response_state *state)
475 : {
476 64 : struct http_request *resp = state->response;
477 64 : struct http_chunk *chunk = NULL;
478 64 : size_t total = 0;
479 64 : size_t prev = 0;
480 :
481 64 : if (state->buffer.length < resp->remaining_content_length) {
482 32 : return HTTP_MORE_DATA_EXPECTED;
483 : }
484 :
485 92 : for (chunk = state->chunks; chunk; chunk = chunk->next) {
486 60 : total += chunk->blob.length;
487 : }
488 :
489 32 : prev = total;
490 32 : total = total + state->buffer.length;
491 32 : if (total < prev) {
492 0 : DBG_ERR("adding chunklen %zu to buf len %zu "
493 : "will overflow\n",
494 : state->buffer.length,
495 : prev);
496 0 : return HTTP_DATA_CORRUPTED;
497 : }
498 32 : if (total > state->max_content_length) {
499 2 : DBG_DEBUG("size %zu exceeds "
500 : "max content len %"PRIu64" skipping body\n",
501 : total,
502 : state->max_content_length);
503 2 : state->parser_state = HTTP_READING_DONE;
504 2 : goto out;
505 : }
506 :
507 : /* chunk read */
508 30 : chunk = talloc_zero(state, struct http_chunk);
509 30 : if (chunk == NULL) {
510 0 : DBG_ERR("%s: Memory error\n", __func__);
511 0 : return HTTP_DATA_CORRUPTED;
512 : }
513 30 : chunk->blob = state->buffer;
514 30 : talloc_steal(chunk, chunk->blob.data);
515 30 : DLIST_ADD_END(state->chunks, chunk);
516 30 : state->parser_state = HTTP_READING_CHUNK_TERM;
517 32 : out:
518 32 : state->buffer = data_blob_null;
519 32 : resp->remaining_content_length = 0;
520 32 : return HTTP_ALL_DATA_READ;
521 : }
522 :
523 0 : static enum http_read_status http_read_trailer(struct http_read_response_state *state)
524 : {
525 0 : enum http_read_status status = HTTP_DATA_CORRUPTED;
526 : /* TODO */
527 0 : return status;
528 : }
529 :
530 3544 : static enum http_read_status http_parse_buffer(struct http_read_response_state *state)
531 : {
532 3544 : if (!state) {
533 0 : DEBUG(0, ("%s: Invalid parameter\n", __func__));
534 0 : return HTTP_DATA_CORRUPTED;
535 : }
536 :
537 3544 : switch (state->parser_state) {
538 340 : case HTTP_READING_FIRSTLINE:
539 340 : return http_parse_firstline(state);
540 2938 : case HTTP_READING_HEADERS:
541 2938 : return http_parse_headers(state);
542 16 : case HTTP_READING_BODY:
543 16 : return http_read_body(state);
544 0 : break;
545 72 : case HTTP_READING_FINAL_CHUNK_TERM:
546 : case HTTP_READING_CHUNK_TERM:
547 72 : return http_read_chunk_term(state);
548 0 : break;
549 114 : case HTTP_READING_CHUNK_SIZE:
550 114 : return http_read_chunk_size(state);
551 0 : break;
552 64 : case HTTP_READING_CHUNK:
553 64 : return http_read_chunk(state);
554 : break;
555 0 : case HTTP_READING_TRAILER:
556 0 : return http_read_trailer(state);
557 0 : break;
558 0 : case HTTP_READING_DONE:
559 : /* All read */
560 0 : return HTTP_ALL_DATA_READ;
561 0 : default:
562 0 : DEBUG(0, ("%s: Illegal parser state %d\n", __func__,
563 : state->parser_state));
564 0 : break;
565 : }
566 0 : return HTTP_DATA_CORRUPTED;
567 : }
568 :
569 180 : static int http_header_is_valid_value(const char *value)
570 : {
571 180 : const char *p = NULL;
572 :
573 : /* Sanity checks */
574 180 : if (!value) {
575 0 : DEBUG(0, ("%s: Invalid parameter\n", __func__));
576 0 : return -1;
577 : }
578 180 : p = value;
579 :
580 180 : while ((p = strpbrk(p, "\r\n")) != NULL) {
581 : /* Expect only one new line */
582 0 : p += strspn(p, "\r\n");
583 : /* Expect a space or tab for continuation */
584 0 : if (*p != ' ' && *p != '\t')
585 0 : return (0);
586 : }
587 180 : return 1;
588 : }
589 :
590 180 : static int http_add_header_internal(TALLOC_CTX *mem_ctx,
591 : struct http_header **headers,
592 : const char *key, const char *value,
593 : bool replace)
594 : {
595 180 : struct http_header *tail = NULL;
596 180 : struct http_header *h = NULL;
597 :
598 : /* Sanity checks */
599 180 : if (!headers || !key || !value) {
600 0 : DEBUG(0, ("Invalid parameter\n"));
601 0 : return -1;
602 : }
603 :
604 :
605 :
606 180 : if (replace) {
607 0 : for (h = *headers; h != NULL; h = h->next) {
608 0 : if (strcasecmp(key, h->key) == 0) {
609 0 : break;
610 : }
611 : }
612 :
613 0 : if (h != NULL) {
614 : /* Replace header value */
615 0 : if (h->value) {
616 0 : talloc_free(h->value);
617 : }
618 0 : h->value = talloc_strdup(h, value);
619 0 : DEBUG(11, ("%s: Replaced HTTP header: key '%s', value '%s'\n",
620 : __func__, h->key, h->value));
621 0 : return 0;
622 : }
623 : }
624 :
625 : /* Add new header */
626 180 : h = talloc(mem_ctx, struct http_header);
627 180 : h->key = talloc_strdup(h, key);
628 180 : h->value = talloc_strdup(h, value);
629 180 : DLIST_ADD_END(*headers, h);
630 180 : tail = DLIST_TAIL(*headers);
631 180 : if (tail != h) {
632 0 : DEBUG(0, ("%s: Error adding header\n", __func__));
633 0 : return -1;
634 : }
635 180 : DEBUG(11, ("%s: Added HTTP header: key '%s', value '%s'\n",
636 : __func__, h->key, h->value));
637 180 : return 0;
638 : }
639 :
640 180 : int http_add_header(TALLOC_CTX *mem_ctx,
641 : struct http_header **headers,
642 : const char *key, const char *value)
643 : {
644 180 : if (strchr(key, '\r') != NULL || strchr(key, '\n') != NULL) {
645 0 : DEBUG(0, ("%s: Dropping illegal header key\n", __func__));
646 0 : return -1;
647 : }
648 :
649 180 : if (!http_header_is_valid_value(value)) {
650 0 : DEBUG(0, ("%s: Dropping illegal header value\n", __func__));
651 0 : return -1;
652 : }
653 :
654 180 : return (http_add_header_internal(mem_ctx, headers, key, value, false));
655 : }
656 :
657 0 : int http_replace_header(TALLOC_CTX *mem_ctx,
658 : struct http_header **headers,
659 : const char *key, const char *value)
660 : {
661 0 : if (strchr(key, '\r') != NULL || strchr(key, '\n') != NULL) {
662 0 : DEBUG(0, ("%s: Dropping illegal header key\n", __func__));
663 0 : return -1;
664 : }
665 :
666 0 : if (!http_header_is_valid_value(value)) {
667 0 : DEBUG(0, ("%s: Dropping illegal header value\n", __func__));
668 0 : return -1;
669 : }
670 :
671 0 : return (http_add_header_internal(mem_ctx, headers, key, value, true));
672 : }
673 :
674 : /**
675 : * Remove a header from the headers list.
676 : *
677 : * Returns 0, if the header was successfully removed.
678 : * Returns -1, if the header could not be found.
679 : */
680 0 : int http_remove_header(struct http_header **headers, const char *key)
681 : {
682 0 : struct http_header *header;
683 :
684 : /* Sanity checks */
685 0 : if (!headers || !key) {
686 0 : DEBUG(0, ("%s: Invalid parameter\n", __func__));
687 0 : return -1;
688 : }
689 :
690 0 : for(header = *headers; header != NULL; header = header->next) {
691 0 : if (strcmp(key, header->key) == 0) {
692 0 : DLIST_REMOVE(*headers, header);
693 0 : return 0;
694 : }
695 : }
696 0 : return -1;
697 : }
698 :
699 3564 : static int http_read_response_next_vector(struct tstream_context *stream,
700 : void *private_data,
701 : TALLOC_CTX *mem_ctx,
702 : struct iovec **_vector,
703 : size_t *_count)
704 : {
705 0 : struct http_read_response_state *state;
706 0 : struct iovec *vector;
707 :
708 : /* Sanity checks */
709 3564 : if (!stream || !private_data || !_vector || !_count) {
710 0 : DEBUG(0, ("%s: Invalid Parameter\n", __func__));
711 0 : return -1;
712 : }
713 :
714 3564 : state = talloc_get_type_abort(private_data, struct http_read_response_state);
715 3564 : vector = talloc_array(mem_ctx, struct iovec, 1);
716 3564 : if (!vector) {
717 0 : DEBUG(0, ("%s: No more memory\n", __func__));
718 0 : return -1;
719 : }
720 :
721 3564 : if (state->buffer.data == NULL) {
722 : /* Allocate buffer */
723 20 : state->buffer.data = talloc_zero_array(state, uint8_t, 1);
724 20 : if (!state->buffer.data) {
725 0 : DEBUG(0, ("%s: No more memory\n", __func__));
726 0 : return -1;
727 : }
728 20 : state->buffer.length = 1;
729 :
730 : /* Return now, nothing to parse yet */
731 20 : vector[0].iov_base = (void *)(state->buffer.data);
732 20 : vector[0].iov_len = 1;
733 20 : *_vector = vector;
734 20 : *_count = 1;
735 20 : return 0;
736 : }
737 :
738 3544 : switch (http_parse_buffer(state)) {
739 232 : case HTTP_ALL_DATA_READ:
740 232 : if (state->parser_state == HTTP_READING_DONE) {
741 : /* Full request or response parsed */
742 18 : *_vector = NULL;
743 18 : *_count = 0;
744 : } else {
745 : /* Free current buffer and allocate new one */
746 214 : TALLOC_FREE(state->buffer.data);
747 214 : state->buffer.data = talloc_zero_array(state, uint8_t, 1);
748 214 : if (!state->buffer.data) {
749 0 : return -1;
750 : }
751 214 : state->buffer.length = 1;
752 :
753 214 : vector[0].iov_base = (void *)(state->buffer.data);
754 214 : vector[0].iov_len = 1;
755 214 : *_vector = vector;
756 214 : *_count = 1;
757 : }
758 232 : break;
759 3310 : case HTTP_MORE_DATA_EXPECTED: {
760 3310 : size_t toread = 1;
761 0 : size_t total;
762 3310 : if (state->parser_state == HTTP_READING_BODY ||
763 3302 : state->parser_state == HTTP_READING_CHUNK) {
764 40 : struct http_request *resp = state->response;
765 40 : toread = resp->remaining_content_length -
766 40 : state->buffer.length;
767 : }
768 :
769 3310 : total = toread + state->buffer.length;
770 :
771 3310 : if (total < state->buffer.length) {
772 0 : DBG_ERR("adding %zu to buf len %zu "
773 : "will overflow\n",
774 : toread,
775 : state->buffer.length);
776 0 : return -1;
777 : }
778 :
779 : /*
780 : * test if content-length message exceeds the
781 : * specified max_content_length
782 : * Note: This check won't be hit at the moment
783 : * due to an existing check in parse_headers
784 : * which will skip the body. Check is here
785 : * for completeness and to cater for future
786 : * code changes.
787 : */
788 3310 : if (state->parser_state == HTTP_READING_BODY) {
789 8 : if (total > state->max_content_length) {
790 0 : DBG_ERR("content size %zu exceeds "
791 : "max content len %"PRIu64"\n",
792 : total,
793 : state->max_content_length);
794 0 : return -1;
795 : }
796 : }
797 :
798 3310 : state->buffer.data =
799 3310 : talloc_realloc(state, state->buffer.data,
800 : uint8_t,
801 : state->buffer.length + toread);
802 3310 : if (!state->buffer.data) {
803 0 : return -1;
804 : }
805 3310 : state->buffer.length += toread;
806 3310 : vector[0].iov_base = (void *)(state->buffer.data +
807 3310 : state->buffer.length - toread);
808 3310 : vector[0].iov_len = toread;
809 3310 : *_vector = vector;
810 3310 : *_count = 1;
811 3310 : break;
812 : }
813 2 : case HTTP_DATA_CORRUPTED:
814 : case HTTP_REQUEST_CANCELED:
815 : case HTTP_DATA_TOO_LONG:
816 2 : return -1;
817 0 : break;
818 0 : default:
819 0 : DEBUG(0, ("%s: Unexpected status\n", __func__));
820 0 : break;
821 : }
822 3542 : return 0;
823 : }
824 :
825 :
826 : /**
827 : * Reads a HTTP response
828 : */
829 : static void http_read_response_done(struct tevent_req *);
830 20 : struct tevent_req *http_read_response_send(TALLOC_CTX *mem_ctx,
831 : struct tevent_context *ev,
832 : struct http_conn *http_conn,
833 : size_t max_content_length)
834 : {
835 0 : struct tevent_req *req;
836 0 : struct tevent_req *subreq;
837 0 : struct http_read_response_state *state;
838 :
839 20 : DEBUG(11, ("%s: Reading HTTP response\n", __func__));
840 :
841 : /* Sanity checks */
842 20 : if (ev == NULL || http_conn == NULL) {
843 0 : DEBUG(0, ("%s: Invalid parameter\n", __func__));
844 0 : return NULL;
845 : }
846 :
847 20 : req = tevent_req_create(mem_ctx, &state, struct http_read_response_state);
848 20 : if (req == NULL) {
849 0 : return NULL;
850 : }
851 :
852 20 : state->max_headers_size = HTTP_MAX_HEADER_SIZE;
853 20 : state->max_content_length = (uint64_t)max_content_length;
854 20 : state->parser_state = HTTP_READING_FIRSTLINE;
855 20 : state->response = talloc_zero(state, struct http_request);
856 20 : if (tevent_req_nomem(state->response, req)) {
857 0 : return tevent_req_post(req, ev);
858 : }
859 :
860 20 : subreq = tstream_readv_pdu_send(state, ev, http_conn->tstreams.active,
861 : http_read_response_next_vector,
862 : state);
863 20 : if (tevent_req_nomem(subreq,req)) {
864 0 : return tevent_req_post(req, ev);
865 : }
866 20 : tevent_req_set_callback(subreq, http_read_response_done, req);
867 :
868 20 : return req;
869 : }
870 :
871 20 : static void http_read_response_done(struct tevent_req *subreq)
872 : {
873 0 : NTSTATUS status;
874 0 : struct tevent_req *req;
875 0 : enum http_body_type ret;
876 0 : int sys_errno;
877 :
878 20 : if (!subreq) {
879 0 : DEBUG(0, ("%s: Invalid parameter\n", __func__));
880 2 : return;
881 : }
882 :
883 20 : req = tevent_req_callback_data(subreq, struct tevent_req);
884 :
885 20 : ret = tstream_readv_pdu_recv(subreq, &sys_errno);
886 20 : DEBUG(11, ("%s: HTTP response read (%d bytes)\n", __func__, ret));
887 20 : TALLOC_FREE(subreq);
888 20 : if (ret == -1) {
889 2 : status = map_nt_error_from_unix_common(sys_errno);
890 2 : DEBUG(0, ("%s: Failed to read HTTP response: %s\n",
891 : __func__, nt_errstr(status)));
892 2 : tevent_req_nterror(req, status);
893 2 : return;
894 : }
895 :
896 18 : tevent_req_done(req);
897 : }
898 :
899 20 : NTSTATUS http_read_response_recv(struct tevent_req *req,
900 : TALLOC_CTX *mem_ctx,
901 : struct http_request **response)
902 : {
903 0 : NTSTATUS status;
904 0 : struct http_read_response_state *state;
905 :
906 20 : if (!mem_ctx || !response || !req) {
907 0 : DEBUG(0, ("%s: Invalid parameter\n", __func__));
908 0 : return NT_STATUS_INVALID_PARAMETER;
909 : }
910 20 : if (tevent_req_is_nterror(req, &status)) {
911 2 : tevent_req_received(req);
912 2 : return status;
913 : }
914 :
915 18 : state = tevent_req_data(req, struct http_read_response_state);
916 18 : *response = state->response;
917 18 : talloc_steal(mem_ctx, state->response);
918 :
919 18 : tevent_req_received(req);
920 :
921 18 : return NT_STATUS_OK;
922 : }
923 :
924 20 : static const char *http_method_str(enum http_cmd_type type)
925 : {
926 0 : const char *method;
927 :
928 20 : switch (type) {
929 20 : case HTTP_REQ_POST:
930 20 : method = "POST";
931 20 : break;
932 0 : case HTTP_REQ_RPC_IN_DATA:
933 0 : method = "RPC_IN_DATA";
934 0 : break;
935 0 : case HTTP_REQ_RPC_OUT_DATA:
936 0 : method = "RPC_OUT_DATA";
937 0 : break;
938 0 : default:
939 0 : method = NULL;
940 0 : break;
941 : }
942 :
943 20 : return method;
944 : }
945 :
946 20 : static NTSTATUS http_push_request_line(TALLOC_CTX *mem_ctx,
947 : DATA_BLOB *buffer,
948 : const struct http_request *req)
949 : {
950 0 : const char *method;
951 0 : char *str;
952 :
953 : /* Sanity checks */
954 20 : if (!buffer || !req) {
955 0 : DEBUG(0, ("%s: Invalid parameter\n", __func__));
956 0 : return NT_STATUS_INVALID_PARAMETER;
957 : }
958 :
959 20 : method = http_method_str(req->type);
960 20 : if (method == NULL) {
961 0 : return NT_STATUS_INVALID_PARAMETER;
962 : }
963 :
964 20 : str = talloc_asprintf(mem_ctx, "%s %s HTTP/%c.%c\r\n", method,
965 20 : req->uri, req->major, req->minor);
966 20 : if (str == NULL)
967 0 : return NT_STATUS_NO_MEMORY;
968 :
969 20 : if (!data_blob_append(mem_ctx, buffer, str, strlen(str))) {
970 0 : talloc_free(str);
971 0 : return NT_STATUS_NO_MEMORY;
972 : }
973 :
974 20 : talloc_free(str);
975 20 : return NT_STATUS_OK;
976 : }
977 :
978 20 : static NTSTATUS http_push_headers(TALLOC_CTX *mem_ctx,
979 : DATA_BLOB *blob,
980 : struct http_request *req)
981 : {
982 20 : struct http_header *header = NULL;
983 20 : char *header_str = NULL;
984 0 : size_t len;
985 :
986 : /* Sanity checks */
987 20 : if (!blob || !req) {
988 0 : DEBUG(0, ("%s: Invalid parameter\n", __func__));
989 0 : return NT_STATUS_INVALID_PARAMETER;
990 : }
991 :
992 92 : for (header = req->headers; header != NULL; header = header->next) {
993 72 : header_str = talloc_asprintf(mem_ctx, "%s: %s\r\n",
994 : header->key, header->value);
995 72 : if (header_str == NULL) {
996 0 : return NT_STATUS_NO_MEMORY;
997 : }
998 :
999 72 : len = strlen(header_str);
1000 72 : if (!data_blob_append(mem_ctx, blob, header_str, len)) {
1001 0 : talloc_free(header_str);
1002 0 : return NT_STATUS_NO_MEMORY;
1003 : }
1004 72 : talloc_free(header_str);
1005 : }
1006 :
1007 20 : if (!data_blob_append(mem_ctx, blob, "\r\n",2)) {
1008 0 : return NT_STATUS_NO_MEMORY;
1009 : }
1010 :
1011 20 : return NT_STATUS_OK;
1012 : }
1013 :
1014 :
1015 20 : static NTSTATUS http_push_body(TALLOC_CTX *mem_ctx,
1016 : DATA_BLOB *blob,
1017 : struct http_request *req)
1018 : {
1019 : /* Sanity checks */
1020 20 : if (!blob || !req) {
1021 0 : DEBUG(0, ("%s: Invalid parameter\n", __func__));
1022 0 : return NT_STATUS_INVALID_PARAMETER;
1023 : }
1024 :
1025 20 : if (req->body.length) {
1026 6 : if (!data_blob_append(mem_ctx, blob, req->body.data,
1027 : req->body.length)) {
1028 0 : return NT_STATUS_NO_MEMORY;
1029 : }
1030 : }
1031 :
1032 20 : return NT_STATUS_OK;
1033 : }
1034 :
1035 : struct http_send_request_state {
1036 : struct tevent_context *ev;
1037 : struct loadparm_context *lp_ctx;
1038 : struct cli_credentials *credentials;
1039 : struct http_request *request;
1040 : DATA_BLOB buffer;
1041 : struct iovec iov;
1042 : ssize_t nwritten;
1043 : int sys_errno;
1044 : };
1045 :
1046 : /**
1047 : * Sends and HTTP request
1048 : */
1049 : static void http_send_request_done(struct tevent_req *);
1050 20 : struct tevent_req *http_send_request_send(TALLOC_CTX *mem_ctx,
1051 : struct tevent_context *ev,
1052 : struct http_conn *http_conn,
1053 : struct http_request *request)
1054 : {
1055 0 : struct tevent_req *req;
1056 0 : struct tevent_req *subreq;
1057 20 : struct http_send_request_state *state = NULL;
1058 0 : NTSTATUS status;
1059 :
1060 20 : DEBUG(11, ("%s: Sending HTTP request\n", __func__));
1061 :
1062 : /* Sanity checks */
1063 20 : if (ev == NULL || request == NULL || http_conn == NULL) {
1064 0 : DEBUG(0, ("%s: Invalid parameter\n", __func__));
1065 0 : return NULL;
1066 : }
1067 :
1068 20 : req = tevent_req_create(mem_ctx, &state, struct http_send_request_state);
1069 20 : if (req == NULL) {
1070 0 : return NULL;
1071 : }
1072 :
1073 20 : state->ev = ev;
1074 20 : state->request = request;
1075 :
1076 : /* Push the request line */
1077 20 : status = http_push_request_line(state, &state->buffer, state->request);
1078 20 : if (!NT_STATUS_IS_OK(status)) {
1079 0 : tevent_req_nterror(req, status);
1080 0 : return tevent_req_post(req, ev);
1081 : }
1082 :
1083 : /* Push the headers */
1084 20 : status = http_push_headers(mem_ctx, &state->buffer, request);
1085 20 : if (!NT_STATUS_IS_OK(status)) {
1086 0 : tevent_req_nterror(req, status);
1087 0 : return tevent_req_post(req, ev);
1088 : }
1089 :
1090 : /* Push the body */
1091 20 : status = http_push_body(mem_ctx, &state->buffer, request);
1092 20 : if (!NT_STATUS_IS_OK(status)) {
1093 0 : tevent_req_nterror(req, status);
1094 0 : return tevent_req_post(req, ev);
1095 : }
1096 :
1097 20 : state->iov.iov_base = (char *) state->buffer.data;
1098 20 : state->iov.iov_len = state->buffer.length;
1099 20 : subreq = tstream_writev_queue_send(state,
1100 : ev,
1101 : http_conn->tstreams.active,
1102 : http_conn->send_queue,
1103 20 : &state->iov, 1);
1104 20 : if (tevent_req_nomem(subreq, req)) {
1105 0 : return tevent_req_post(req, ev);
1106 : }
1107 20 : tevent_req_set_callback(subreq, http_send_request_done, req);
1108 :
1109 20 : return req;
1110 : }
1111 :
1112 20 : static void http_send_request_done(struct tevent_req *subreq)
1113 : {
1114 0 : NTSTATUS status;
1115 0 : struct tevent_req *req;
1116 0 : struct http_send_request_state *state;
1117 :
1118 20 : req = tevent_req_callback_data(subreq, struct tevent_req);
1119 20 : state = tevent_req_data(req, struct http_send_request_state);
1120 :
1121 20 : state->nwritten = tstream_writev_queue_recv(subreq, &state->sys_errno);
1122 20 : TALLOC_FREE(subreq);
1123 20 : if (state->nwritten == -1 && state->sys_errno != 0) {
1124 0 : status = map_nt_error_from_unix_common(state->sys_errno);
1125 0 : DEBUG(0, ("%s: Failed to send HTTP request: %s\n",
1126 : __func__, nt_errstr(status)));
1127 0 : tevent_req_nterror(req, status);
1128 0 : return;
1129 : }
1130 :
1131 20 : tevent_req_done(req);
1132 : }
1133 :
1134 20 : NTSTATUS http_send_request_recv(struct tevent_req *req)
1135 : {
1136 0 : NTSTATUS status;
1137 :
1138 20 : if (!req) {
1139 0 : DEBUG(0, ("%s: Invalid parameter\n", __func__));
1140 0 : return NT_STATUS_INVALID_PARAMETER;
1141 : }
1142 :
1143 20 : if (tevent_req_is_nterror(req, &status)) {
1144 0 : tevent_req_received(req);
1145 0 : return status;
1146 : }
1147 :
1148 20 : tevent_req_received(req);
1149 :
1150 20 : return NT_STATUS_OK;
1151 : }
|