]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/libcharon/plugins/tnc_ifmap/tnc_ifmap_http.c
Update copyright headers after acquisition by secunet
[thirdparty/strongswan.git] / src / libcharon / plugins / tnc_ifmap / tnc_ifmap_http.c
CommitLineData
91503c21
AS
1/*
2 * Copyright (C) 2013 Andreas Steffen
19ef2aec
TB
3 *
4 * Copyright (C) secunet Security Networks AG
91503c21
AS
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17#define _GNU_SOURCE /* for asprintf() */
18
19#include "tnc_ifmap_http.h"
20
21#include <utils/debug.h>
22#include <utils/lexparser.h>
23
24#include <stdio.h>
25
26typedef struct private_tnc_ifmap_http_t private_tnc_ifmap_http_t;
27
28/**
29 * Private data of an tnc_ifmap_http_t object.
30 */
31struct private_tnc_ifmap_http_t {
32
33 /**
34 * Public tnc_ifmap_http_t interface.
35 */
36 tnc_ifmap_http_t public;
37
38 /**
39 * HTTPS Server URI with https:// prefix removed
40 */
41 char *uri;
42
43 /**
44 * Optional base64-encoded username:password for HTTP Basic Authentication
45 */
46 chunk_t user_pass;
47
48 /**
49 * HTTP chunked mode
50 */
51 bool chunked;
52
53};
54
55METHOD(tnc_ifmap_http_t, build, status_t,
56 private_tnc_ifmap_http_t *this, chunk_t *in, chunk_t *out)
57{
58 char *host, *path, *request, auth[128];
59 int len;
60
61 /* Duplicate host[/path] string since we are going to manipulate it */
62 len = strlen(this->uri) + 2;
63 host = malloc(len);
64 memset(host, '\0', len);
65 strcpy(host, this->uri);
66
67 /* Extract appended path or set to root */
68 path = strchr(host, '/');
69 if (!path)
70 {
71 path = host + len - 2;
72 *path = '/';
73 }
74
75 /* Use Basic Authentication? */
76 if (this->user_pass.len)
77 {
78 snprintf(auth, sizeof(auth), "Authorization: Basic %.*s\r\n",
0c76d820 79 (int)this->user_pass.len, this->user_pass.ptr);
91503c21
AS
80 }
81 else
82 {
83 *auth = '\0';
84 }
85
86 /* Write HTTP POST request, TODO break up into chunks */
87 len = asprintf(&request,
88 "POST %s HTTP/1.1\r\n"
89 "Host: %.*s\r\n"
90 "%s"
91 "Content-Type: application/soap+xml;charset=utf-8\r\n"
92 "Content-Length: %d\r\n"
93 "\r\n"
0c76d820
TB
94 "%.*s", path, (int)(path-host), host, auth, (int)in->len,
95 (int)in->len, in->ptr);
91503c21
AS
96 free(host);
97
98 if (len == -1)
99 {
100 return FAILED;
101 }
102 *out = chunk_create(request, len);
3ea6fcb5 103 DBG3(DBG_TLS, "sending HTTP POST request %B", out);
91503c21
AS
104
105 return SUCCESS;
106}
107
108static bool process_header(chunk_t *in, bool *chunked, u_int *content_len)
109{
110 chunk_t line, version, parameter;
111 int code;
112 u_int len;
113
114 /* Process HTTP protocol version */
115 if (!fetchline(in, &line) || !extract_token(&version, ' ', &line) ||
116 !match("HTTP/1.1", &version) || sscanf(line.ptr, "%d", &code) != 1)
117 {
118 DBG1(DBG_TNC, "malformed http response header");
119 return FALSE;
120 }
121 if (code != 200)
122 {
123 DBG1(DBG_TNC, "http response returns error code %d", code);
124 return FALSE;
0c76d820 125 }
91503c21
AS
126
127 *content_len = 0;
128 *chunked = FALSE;
129
130 /* Process HTTP header line by line until the HTTP body is reached */
131 while (fetchline(in, &line))
132 {
133 if (line.len == 0)
134 {
135 break;
136 }
137 if (extract_token(&parameter, ':', &line) && eat_whitespace(&line))
138 {
139 if (match("Content-Length", &parameter))
140 {
141 if (sscanf(line.ptr, "%u", &len) == 1)
142 {
143 *content_len = len;
144 }
145 }
146 else if (match("Transfer-Encoding", &parameter) &&
147 match("chunked", &line))
148 {
149 *chunked = TRUE;
150 }
151 }
152 }
153
154 return TRUE;
155}
156
157METHOD(tnc_ifmap_http_t, process, status_t,
158 private_tnc_ifmap_http_t *this, chunk_t *in, chunk_t *out)
159{
160 u_int len = 0;
161 chunk_t line, out_chunk;
162
163 DBG3(DBG_TLS, "receiving HTTP response %B", in);
164
165 if (!this->chunked)
166 {
167 if (!process_header(in, &this->chunked, &len))
168 {
169 return FAILED;
170 }
171 }
172
173 while (in->len)
174 {
175 if (this->chunked)
176 {
177 if (!fetchline(in, &line) || sscanf(line.ptr, "%x", &len) != 1)
178 {
179 return FAILED;
180 }
181 DBG3(DBG_TLS, "received HTTP response is chunked (%u bytes)", len);
182
183 /* Received last chunk? */
184 if (len == 0)
185 {
186 return SUCCESS;
187 }
188 }
189
190 /* Check size of of remaining HTTP body */
191 if (len > in->len)
192 {
193 DBG1(DBG_TNC, "insufficient data in HTTP body");
194 return FAILED;
195 }
196
197 if (this->chunked)
198 {
199 out_chunk = *in;
200 out_chunk.len = len;
0c76d820 201 *out = chunk_cat("mc", *out, out_chunk);
91503c21
AS
202 *in = chunk_skip(*in, len);
203 if (!fetchline(in, &line) || line.len > 0)
204 {
205 return FAILED;
0c76d820 206 }
91503c21
AS
207 }
208 else
209 {
210 if (len)
211 {
212 in->len = len;
213 }
214 *out = chunk_clone(*in);
215 return SUCCESS;
216 }
217 }
218 return NEED_MORE;
219}
220
221METHOD(tnc_ifmap_http_t, destroy, void,
222 private_tnc_ifmap_http_t *this)
223{
224 free(this);
225}
226
227/**
228 * See header
229 */
230tnc_ifmap_http_t *tnc_ifmap_http_create(char *uri, chunk_t user_pass)
231{
232 private_tnc_ifmap_http_t *this;
233
234 INIT(this,
235 .public = {
236 .build = _build,
237 .process = _process,
238 .destroy = _destroy,
239 },
240 .uri = uri,
241 .user_pass = user_pass,
242 );
243
244 return &this->public;
245}
246