1 // SoftEther VPN Source Code - Stable Edition Repository
2 // Cedar Communication Module
3 //
4 // SoftEther VPN Server, Client and Bridge are free software under the Apache License, Version 2.0.
5 //
6 // Copyright (c) Daiyuu Nobori.
7 // Copyright (c) SoftEther VPN Project, University of Tsukuba, Japan.
8 // Copyright (c) SoftEther Corporation.
9 // Copyright (c) all contributors on SoftEther VPN project in GitHub.
10 //
11 // All Rights Reserved.
12 //
13 // http://www.softether.org/
14 //
15 // This stable branch is officially managed by Daiyuu Nobori, the owner of SoftEther VPN Project.
16 // Pull requests should be sent to the Developer Edition Master Repository on https://github.com/SoftEtherVPN/SoftEtherVPN
17 //
18 // License: The Apache License, Version 2.0
19 // https://www.apache.org/licenses/LICENSE-2.0
20 //
21 // DISCLAIMER
22 // ==========
23 //
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 // SOFTWARE.
31 //
32 // THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN, UNDER
33 // JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY, MERGE, PUBLISH,
34 // DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS SOFTWARE, THAT ANY
35 // JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS SOFTWARE OR ITS CONTENTS,
36 // AGAINST US (SOFTETHER PROJECT, SOFTETHER CORPORATION, DAIYUU NOBORI OR OTHER
37 // SUPPLIERS), OR ANY JURIDICAL DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND
38 // OF USING, COPYING, MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING,
39 // AND/OR SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
40 // CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO EXCLUSIVE
41 // JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO, JAPAN. YOU MUST WAIVE
42 // ALL DEFENSES OF LACK OF PERSONAL JURISDICTION AND FORUM NON CONVENIENS.
43 // PROCESS MAY BE SERVED ON EITHER PARTY IN THE MANNER AUTHORIZED BY APPLICABLE
44 // LAW OR COURT RULE.
45 //
46 // USE ONLY IN JAPAN. DO NOT USE THIS SOFTWARE IN ANOTHER COUNTRY UNLESS YOU HAVE
47 // A CONFIRMATION THAT THIS SOFTWARE DOES NOT VIOLATE ANY CRIMINAL LAWS OR CIVIL
48 // RIGHTS IN THAT PARTICULAR COUNTRY. USING THIS SOFTWARE IN OTHER COUNTRIES IS
49 // COMPLETELY AT YOUR OWN RISK. THE SOFTETHER VPN PROJECT HAS DEVELOPED AND
50 // DISTRIBUTED THIS SOFTWARE TO COMPLY ONLY WITH THE JAPANESE LAWS AND EXISTING
51 // CIVIL RIGHTS INCLUDING PATENTS WHICH ARE SUBJECTS APPLY IN JAPAN. OTHER
52 // COUNTRIES' LAWS OR CIVIL RIGHTS ARE NONE OF OUR CONCERNS NOR RESPONSIBILITIES.
53 // WE HAVE NEVER INVESTIGATED ANY CRIMINAL REGULATIONS, CIVIL LAWS OR
54 // INTELLECTUAL PROPERTY RIGHTS INCLUDING PATENTS IN ANY OF OTHER 200+ COUNTRIES
55 // AND TERRITORIES. BY NATURE, THERE ARE 200+ REGIONS IN THE WORLD, WITH
56 // DIFFERENT LAWS. IT IS IMPOSSIBLE TO VERIFY EVERY COUNTRIES' LAWS, REGULATIONS
57 // AND CIVIL RIGHTS TO MAKE THE SOFTWARE COMPLY WITH ALL COUNTRIES' LAWS BY THE
58 // PROJECT. EVEN IF YOU WILL BE SUED BY A PRIVATE ENTITY OR BE DAMAGED BY A
59 // PUBLIC SERVANT IN YOUR COUNTRY, THE DEVELOPERS OF THIS SOFTWARE WILL NEVER BE
60 // LIABLE TO RECOVER OR COMPENSATE SUCH DAMAGES, CRIMINAL OR CIVIL
61 // RESPONSIBILITIES. NOTE THAT THIS LINE IS NOT LICENSE RESTRICTION BUT JUST A
62 // STATEMENT FOR WARNING AND DISCLAIMER.
63 //
64 // READ AND UNDERSTAND THE 'WARNING.TXT' FILE BEFORE USING THIS SOFTWARE.
65 // SOME SOFTWARE PROGRAMS FROM THIRD PARTIES ARE INCLUDED ON THIS SOFTWARE WITH
66 // LICENSE CONDITIONS WHICH ARE DESCRIBED ON THE 'THIRD_PARTY.TXT' FILE.
67 //
68 //
69 // SOURCE CODE CONTRIBUTION
70 // ------------------------
71 //
72 // Your contribution to SoftEther VPN Project is much appreciated.
73 // Please send patches to us through GitHub.
74 // Read the SoftEther VPN Patch Acceptance Policy in advance:
75 // http://www.softether.org/5-download/src/9.patch
76 //
77 //
78 // DEAR SECURITY EXPERTS
79 // ---------------------
80 //
81 // If you find a bug or a security vulnerability please kindly inform us
82 // about the problem immediately so that we can fix the security problem
83 // to protect a lot of users around the world as soon as possible.
84 //
85 // Our e-mail address for security reports is:
86 // softether-vpn-security [at] softether.org
87 //
88 // Please note that the above e-mail address is not a technical support
89 // inquiry address. If you need technical assistance, please visit
90 // http://www.softether.org/ and ask your question on the users forum.
91 //
92 // Thank you for your cooperation.
93 //
94 //
95 // NO MEMORY OR RESOURCE LEAKS
96 // ---------------------------
97 //
98 // The memory-leaks and resource-leaks verification under the stress
99 // test has been passed before release this source code.
100 
101 
102 // Wpc.c
103 // RPC over HTTP
104 
105 #include <GlobalConst.h>
106 
107 #include "CedarPch.h"
108 
109 // Get whether the proxy server is specified by a private IP
IsProxyPrivateIp(INTERNET_SETTING * s)110 bool IsProxyPrivateIp(INTERNET_SETTING *s)
111 {
112 	IP ip;
113 	// Validate arguments
114 	if (s == NULL)
115 	{
116 		return false;
117 	}
118 
119 	if (s->ProxyType == PROXY_DIRECT)
120 	{
121 		return false;
122 	}
123 
124 	if (GetIP(&ip, s->ProxyHostName) == false)
125 	{
126 		return false;
127 	}
128 
129 	if (IsIPPrivate(&ip))
130 	{
131 		return true;
132 	}
133 
134 	if (IsIPMyHost(&ip))
135 	{
136 		return true;
137 	}
138 
139 	if (IsLocalHostIP(&ip))
140 	{
141 		return true;
142 	}
143 
144 	return false;
145 }
146 
147 // Call
WpcCall(char * url,INTERNET_SETTING * setting,UINT timeout_connect,UINT timeout_comm,char * function_name,PACK * pack,X * cert,K * key,void * sha1_cert_hash)148 PACK *WpcCall(char *url, INTERNET_SETTING *setting, UINT timeout_connect, UINT timeout_comm,
149 			  char *function_name, PACK *pack, X *cert, K *key, void *sha1_cert_hash)
150 {
151 	return WpcCallEx(url, setting, timeout_connect, timeout_comm, function_name, pack, cert, key,
152 		sha1_cert_hash, NULL, 0, NULL, NULL);
153 }
WpcCallEx(char * url,INTERNET_SETTING * setting,UINT timeout_connect,UINT timeout_comm,char * function_name,PACK * pack,X * cert,K * key,void * sha1_cert_hash,bool * cancel,UINT max_recv_size,char * additional_header_name,char * additional_header_value)154 PACK *WpcCallEx(char *url, INTERNET_SETTING *setting, UINT timeout_connect, UINT timeout_comm,
155 				char *function_name, PACK *pack, X *cert, K *key, void *sha1_cert_hash, bool *cancel, UINT max_recv_size,
156 				char *additional_header_name, char *additional_header_value)
157 {
158 	return WpcCallEx2(url, setting, timeout_connect, timeout_comm, function_name, pack,
159 		cert, key, sha1_cert_hash, (sha1_cert_hash == NULL ? 0 : 1),
160 		cancel, max_recv_size, additional_header_name, additional_header_value, NULL);
161 }
WpcCallEx2(char * url,INTERNET_SETTING * setting,UINT timeout_connect,UINT timeout_comm,char * function_name,PACK * pack,X * cert,K * key,void * sha1_cert_hash,UINT num_hashes,bool * cancel,UINT max_recv_size,char * additional_header_name,char * additional_header_value,char * sni_string)162 PACK *WpcCallEx2(char *url, INTERNET_SETTING *setting, UINT timeout_connect, UINT timeout_comm,
163 				char *function_name, PACK *pack, X *cert, K *key, void *sha1_cert_hash, UINT num_hashes, bool *cancel, UINT max_recv_size,
164 				char *additional_header_name, char *additional_header_value, char *sni_string)
165 {
166 	URL_DATA data;
167 	BUF *b, *recv;
168 	UINT error;
169 	WPC_PACKET packet;
170 	// Validate arguments
171 	if (function_name == NULL || pack == NULL)
172 	{
173 		return PackError(ERR_INTERNAL_ERROR);
174 	}
175 
176 	if (ParseUrl(&data, url, true, NULL) == false)
177 	{
178 		return PackError(ERR_INTERNAL_ERROR);
179 	}
180 
181 	PackAddStr(pack, "function", function_name);
182 
183 	b = WpcGeneratePacket(pack, cert, key);
184 	if (b == NULL)
185 	{
186 		return PackError(ERR_INTERNAL_ERROR);
187 	}
188 
189 	SeekBuf(b, b->Size, 0);
190 	WriteBufInt(b, 0);
191 	SeekBuf(b, 0, 0);
192 
193 	if (IsEmptyStr(additional_header_name) == false && IsEmptyStr(additional_header_value) == false)
194 	{
195 		StrCpy(data.AdditionalHeaderName, sizeof(data.AdditionalHeaderName), additional_header_name);
196 		StrCpy(data.AdditionalHeaderValue, sizeof(data.AdditionalHeaderValue), additional_header_value);
197 	}
198 
199 	if (sni_string != NULL && IsEmptyStr(sni_string) == false)
200 	{
201 		StrCpy(data.SniString, sizeof(data.SniString), sni_string);
202 	}
203 
204 	recv = HttpRequestEx3(&data, setting, timeout_connect, timeout_comm, &error,
205 		false, b->Buf, NULL, NULL, sha1_cert_hash, num_hashes, cancel, max_recv_size,
206 		NULL, NULL);
207 
208 	FreeBuf(b);
209 
210 	if (recv == NULL)
211 	{
212 		return PackError(error);
213 	}
214 
215 	if (WpcParsePacket(&packet, recv) == false)
216 	{
217 		FreeBuf(recv);
218 		return PackError(ERR_PROTOCOL_ERROR);
219 	}
220 
221 	FreeBuf(recv);
222 
223 	FreeX(packet.Cert);
224 
225 	return packet.Pack;
226 }
227 
228 // Release the packet
WpcFreePacket(WPC_PACKET * packet)229 void WpcFreePacket(WPC_PACKET *packet)
230 {
231 	// Validate arguments
232 	if (packet == NULL)
233 	{
234 		return;
235 	}
236 
237 	FreePack(packet->Pack);
238 	FreeX(packet->Cert);
239 }
240 
241 // Parse the packet
WpcParsePacket(WPC_PACKET * packet,BUF * buf)242 bool WpcParsePacket(WPC_PACKET *packet, BUF *buf)
243 {
244 	LIST *o;
245 	BUF *b;
246 	bool ret = false;
247 	UCHAR hash[SHA1_SIZE];
248 	// Validate arguments
249 	if (packet == NULL || buf == NULL)
250 	{
251 		return false;
252 	}
253 
254 	Zero(packet, sizeof(WPC_PACKET));
255 
256 	o = WpcParseDataEntry(buf);
257 
258 	b = WpcDataEntryToBuf(WpcFindDataEntry(o, "PACK"));
259 	if (b != NULL)
260 	{
261 		HashSha1(hash, b->Buf, b->Size);
262 
263 		packet->Pack = BufToPack(b);
264 		FreeBuf(b);
265 
266 		if (packet->Pack != NULL)
267 		{
268 			BUF *b;
269 
270 			ret = true;
271 
272 			b = WpcDataEntryToBuf(WpcFindDataEntry(o, "HASH"));
273 
274 			if (b != NULL)
275 			{
276 				if (b->Size != SHA1_SIZE || Cmp(b->Buf, hash, SHA1_SIZE) != 0)
277 				{
278 					ret = false;
279 					FreePack(packet->Pack);
280 				}
281 				else
282 				{
283 					BUF *b;
284 
285 					Copy(packet->Hash, hash, SHA1_SIZE);
286 
287 					b = WpcDataEntryToBuf(WpcFindDataEntry(o, "CERT"));
288 
289 					if (b != NULL)
290 					{
291 						X *cert = BufToX(b, false);
292 						if (cert == NULL)
293 						{
294 							ret = false;
295 							FreePack(packet->Pack);
296 						}
297 						else
298 						{
299 							BUF *b = WpcDataEntryToBuf(WpcFindDataEntry(o, "SIGN"));
300 
301 							if (b == NULL || (b->Size != 128))
302 							{
303 								ret = false;
304 								FreeX(cert);
305 								FreePack(packet->Pack);
306 							}
307 							else
308 							{
309 								K *k = GetKFromX(cert);
310 
311 								if (RsaVerify(hash, SHA1_SIZE, b->Buf, k) == false)
312 								{
313 									ret = false;
314 									FreeX(cert);
315 									FreePack(packet->Pack);
316 								}
317 								else
318 								{
319 									packet->Cert = cert;
320 									Copy(packet->Sign, b->Buf, 128);
321 								}
322 
323 								FreeK(k);
324 							}
325 
326 							FreeBuf(b);
327 						}
328 						FreeBuf(b);
329 					}
330 				}
331 				FreeBuf(b);
332 			}
333 		}
334 	}
335 
336 	WpcFreeDataEntryList(o);
337 
338 	return ret;
339 }
340 
341 // Generate the packet
WpcGeneratePacket(PACK * pack,X * cert,K * key)342 BUF *WpcGeneratePacket(PACK *pack, X *cert, K *key)
343 {
344 	UCHAR hash[SHA1_SIZE];
345 	BUF *pack_data;
346 	BUF *cert_data = NULL;
347 	BUF *sign_data = NULL;
348 	BUF *b;
349 	// Validate arguments
350 	if (pack == NULL)
351 	{
352 		return NULL;
353 	}
354 
355 	pack_data = PackToBuf(pack);
356 	HashSha1(hash, pack_data->Buf, pack_data->Size);
357 
358 	if (cert != NULL && key != NULL)
359 	{
360 		UCHAR sign[128];
361 		cert_data = XToBuf(cert, false);
362 
363 		RsaSign(sign, hash, sizeof(hash), key);
364 
365 		sign_data = NewBuf();
366 		WriteBuf(sign_data, sign, sizeof(sign));
367 		SeekBuf(sign_data, 0, 0);
368 	}
369 
370 	b = NewBuf();
371 
372 	WpcAddDataEntryBin(b, "PACK", pack_data->Buf, pack_data->Size);
373 	WpcAddDataEntryBin(b, "HASH", hash, sizeof(hash));
374 
375 	if (cert_data != NULL)
376 	{
377 		WpcAddDataEntryBin(b, "CERT", cert_data->Buf, cert_data->Size);
378 		WpcAddDataEntryBin(b, "SIGN", sign_data->Buf, sign_data->Size);
379 	}
380 
381 	FreeBuf(pack_data);
382 	FreeBuf(cert_data);
383 	FreeBuf(sign_data);
384 
385 	SeekBuf(b, 0, 0);
386 
387 	return b;
388 }
389 
390 // Decode the buffer from WPC_ENTRY
WpcDataEntryToBuf(WPC_ENTRY * e)391 BUF *WpcDataEntryToBuf(WPC_ENTRY *e)
392 {
393 	void *data;
394 	UINT data_size;
395 	UINT size;
396 	BUF *b;
397 	// Validate arguments
398 	if (e == NULL)
399 	{
400 		return NULL;
401 	}
402 
403 	data_size = e->Size + 4096;
404 	data = Malloc(data_size);
405 	size = DecodeSafe64(data, e->Data, e->Size);
406 
407 	b = NewBuf();
408 	WriteBuf(b, data, size);
409 	SeekBuf(b, 0, 0);
410 
411 	Free(data);
412 
413 	return b;
414 }
415 
416 // Search for the data entry
WpcFindDataEntry(LIST * o,char * name)417 WPC_ENTRY *WpcFindDataEntry(LIST *o, char *name)
418 {
419 	UINT i;
420 	char name_str[WPC_DATA_ENTRY_SIZE];
421 	// Validate arguments
422 	if (o == NULL || name == NULL)
423 	{
424 		return NULL;
425 	}
426 
427 	WpcFillEntryName(name_str, name);
428 
429 	for (i = 0;i < LIST_NUM(o);i++)
430 	{
431 		WPC_ENTRY *e = LIST_DATA(o, i);
432 
433 		if (Cmp(e->EntryName, name_str, WPC_DATA_ENTRY_SIZE) == 0)
434 		{
435 			return e;
436 		}
437 	}
438 
439 	return NULL;
440 }
441 
442 // Release the data entry list
WpcFreeDataEntryList(LIST * o)443 void WpcFreeDataEntryList(LIST *o)
444 {
445 	UINT i;
446 	// Validate arguments
447 	if (o == NULL)
448 	{
449 		return;
450 	}
451 
452 	for (i = 0;i < LIST_NUM(o);i++)
453 	{
454 		WPC_ENTRY *e = LIST_DATA(o, i);
455 
456 		Free(e);
457 	}
458 
459 	ReleaseList(o);
460 }
461 
462 // Parse the data entry
WpcParseDataEntry(BUF * b)463 LIST *WpcParseDataEntry(BUF *b)
464 {
465 	char entry_name[WPC_DATA_ENTRY_SIZE];
466 	char size_str[11];
467 	LIST *o;
468 	// Validate arguments
469 	if (b == NULL)
470 	{
471 		return NULL;
472 	}
473 
474 	SeekBuf(b, 0, 0);
475 
476 	o = NewListFast(NULL);
477 
478 	while (true)
479 	{
480 		UINT size;
481 		WPC_ENTRY *e;
482 
483 		if (ReadBuf(b, entry_name, WPC_DATA_ENTRY_SIZE) != WPC_DATA_ENTRY_SIZE)
484 		{
485 			break;
486 		}
487 
488 		Zero(size_str, sizeof(size_str));
489 		if (ReadBuf(b, size_str, 10) != 10)
490 		{
491 			break;
492 		}
493 
494 		size = ToInt(size_str);
495 		if ((b->Size - b->Current) < size)
496 		{
497 			break;
498 		}
499 
500 		e = ZeroMalloc(sizeof(WPC_ENTRY));
501 		e->Data = (UCHAR *)b->Buf + b->Current;
502 		Copy(e->EntryName, entry_name, WPC_DATA_ENTRY_SIZE);
503 		e->Size = size;
504 
505 		SeekBuf(b, size, 1);
506 
507 		Add(o, e);
508 	}
509 
510 	return o;
511 }
512 
513 // Generate a entry name
WpcFillEntryName(char * dst,char * name)514 void WpcFillEntryName(char *dst, char *name)
515 {
516 	UINT i, len;
517 	char tmp[MAX_SIZE];
518 	// Validate arguments
519 	if (dst == NULL || name == NULL)
520 	{
521 		return;
522 	}
523 
524 	StrCpy(tmp, sizeof(tmp), name);
525 	StrUpper(tmp);
526 	len = StrLen(tmp);
527 
528 	for (i = 0;i < WPC_DATA_ENTRY_SIZE;i++)
529 	{
530 		dst[i] = ' ';
531 	}
532 
533 	if (len <= WPC_DATA_ENTRY_SIZE)
534 	{
535 		Copy(dst, tmp, len);
536 	}
537 	else
538 	{
539 		Copy(dst, tmp, WPC_DATA_ENTRY_SIZE);
540 	}
541 }
542 
543 // Add the data entry (binary)
WpcAddDataEntryBin(BUF * b,char * name,void * data,UINT size)544 void WpcAddDataEntryBin(BUF *b, char *name, void *data, UINT size)
545 {
546 	char *str;
547 	// Validate arguments
548 	if (b == NULL || name == NULL || (data == NULL && size != 0))
549 	{
550 		return;
551 	}
552 
553 	str = Malloc(size * 2 + 64);
554 
555 	EncodeSafe64(str, data, size);
556 
557 	WpcAddDataEntry(b, name, str, StrLen(str));
558 
559 	Free(str);
560 }
561 
562 
563 // Add the data entry
WpcAddDataEntry(BUF * b,char * name,void * data,UINT size)564 void WpcAddDataEntry(BUF *b, char *name, void *data, UINT size)
565 {
566 	char entry_name[WPC_DATA_ENTRY_SIZE];
567 	char size_str[11];
568 	// Validate arguments
569 	if (b == NULL || name == NULL || (data == NULL && size != 0))
570 	{
571 		return;
572 	}
573 
574 	WpcFillEntryName(entry_name, name);
575 	WriteBuf(b, entry_name, WPC_DATA_ENTRY_SIZE);
576 
577 	Format(size_str, sizeof(size_str), "%010u", size);
578 	WriteBuf(b, size_str, 10);
579 
580 	WriteBuf(b, data, size);
581 }
582 
583 // Get the empty INTERNET_SETTING
GetNullInternetSetting()584 INTERNET_SETTING *GetNullInternetSetting()
585 {
586 	static INTERNET_SETTING ret;
587 
588 	Zero(&ret, sizeof(ret));
589 
590 	return &ret;
591 }
592 
593 // Socket connection
WpcSockConnect(WPC_CONNECT * param,UINT * error_code,UINT timeout)594 SOCK *WpcSockConnect(WPC_CONNECT *param, UINT *error_code, UINT timeout)
595 {
596 	return WpcSockConnectEx(param, error_code, timeout, NULL);
597 }
WpcSockConnectEx(WPC_CONNECT * param,UINT * error_code,UINT timeout,bool * cancel)598 SOCK *WpcSockConnectEx(WPC_CONNECT *param, UINT *error_code, UINT timeout, bool *cancel)
599 {
600 	CONNECTION c;
601 	SOCK *sock;
602 	UINT err = ERR_NO_ERROR;
603 	// Validate arguments
604 	if (param == NULL)
605 	{
606 		return NULL;
607 	}
608 
609 	Zero(&c, sizeof(c));
610 
611 	sock = NULL;
612 	err = ERR_INTERNAL_ERROR;
613 
614 	switch (param->ProxyType)
615 	{
616 	case PROXY_DIRECT:
617 		sock = TcpConnectEx3(param->HostName, param->Port, timeout, cancel, NULL, true, NULL, false, false, NULL);
618 		if (sock == NULL)
619 		{
620 			err = ERR_CONNECT_FAILED;
621 		}
622 		break;
623 
624 	case PROXY_HTTP:
625 		sock = ProxyConnectEx2(&c, param->ProxyHostName, param->ProxyPort,
626 			param->HostName, param->Port,
627 			param->ProxyUsername, param->ProxyPassword, false, cancel, NULL, timeout);
628 		if (sock == NULL)
629 		{
630 			err = c.Err;
631 		}
632 		break;
633 
634 	case PROXY_SOCKS:
635 		sock = SocksConnectEx2(&c, param->ProxyHostName, param->ProxyPort,
636 			param->HostName, param->Port,
637 			param->ProxyUsername, false, cancel, NULL, timeout, NULL);
638 		if (sock == NULL)
639 		{
640 			err = c.Err;
641 		}
642 		break;
643 	}
644 
645 	if (error_code != NULL)
646 	{
647 		*error_code = err;
648 	}
649 
650 	return sock;
651 }
WpcSockConnect2(char * hostname,UINT port,INTERNET_SETTING * t,UINT * error_code,UINT timeout)652 SOCK *WpcSockConnect2(char *hostname, UINT port, INTERNET_SETTING *t, UINT *error_code, UINT timeout)
653 {
654 	// Validate arguments
655 	INTERNET_SETTING t2;
656 	WPC_CONNECT c;
657 	if (t == NULL)
658 	{
659 		Zero(&t2, sizeof(t2));
660 
661 		t = &t2;
662 	}
663 
664 	Zero(&c, sizeof(c));
665 	StrCpy(c.HostName, sizeof(c.HostName), hostname);
666 	c.Port = port;
667 	c.ProxyType = t->ProxyType;
668 	StrCpy(c.ProxyHostName, sizeof(c.HostName), t->ProxyHostName);
669 	c.ProxyPort = t->ProxyPort;
670 	StrCpy(c.ProxyUsername, sizeof(c.ProxyUsername), t->ProxyUsername);
671 	StrCpy(c.ProxyPassword, sizeof(c.ProxyPassword), t->ProxyPassword);
672 
673 	return WpcSockConnect(&c, error_code, timeout);
674 }
675 
676 // Handle the HTTP request
HttpRequest(URL_DATA * data,INTERNET_SETTING * setting,UINT timeout_connect,UINT timeout_comm,UINT * error_code,bool check_ssl_trust,char * post_data,WPC_RECV_CALLBACK * recv_callback,void * recv_callback_param,void * sha1_cert_hash)677 BUF *HttpRequest(URL_DATA *data, INTERNET_SETTING *setting,
678 				 UINT timeout_connect, UINT timeout_comm,
679 				 UINT *error_code, bool check_ssl_trust, char *post_data,
680 				 WPC_RECV_CALLBACK *recv_callback, void *recv_callback_param, void *sha1_cert_hash)
681 {
682 	return HttpRequestEx(data, setting, timeout_connect, timeout_comm,
683 		error_code, check_ssl_trust, post_data,
684 		recv_callback, recv_callback_param, sha1_cert_hash, NULL, 0);
685 }
HttpRequestEx(URL_DATA * data,INTERNET_SETTING * setting,UINT timeout_connect,UINT timeout_comm,UINT * error_code,bool check_ssl_trust,char * post_data,WPC_RECV_CALLBACK * recv_callback,void * recv_callback_param,void * sha1_cert_hash,bool * cancel,UINT max_recv_size)686 BUF *HttpRequestEx(URL_DATA *data, INTERNET_SETTING *setting,
687 				   UINT timeout_connect, UINT timeout_comm,
688 				   UINT *error_code, bool check_ssl_trust, char *post_data,
689 				   WPC_RECV_CALLBACK *recv_callback, void *recv_callback_param, void *sha1_cert_hash,
690 				   bool *cancel, UINT max_recv_size)
691 {
692 	return HttpRequestEx2(data, setting, timeout_connect, timeout_comm, error_code,
693 		check_ssl_trust, post_data, recv_callback, recv_callback_param, sha1_cert_hash,
694 		cancel, max_recv_size, NULL, NULL);
695 }
HttpRequestEx2(URL_DATA * data,INTERNET_SETTING * setting,UINT timeout_connect,UINT timeout_comm,UINT * error_code,bool check_ssl_trust,char * post_data,WPC_RECV_CALLBACK * recv_callback,void * recv_callback_param,void * sha1_cert_hash,bool * cancel,UINT max_recv_size,char * header_name,char * header_value)696 BUF *HttpRequestEx2(URL_DATA *data, INTERNET_SETTING *setting,
697 				   UINT timeout_connect, UINT timeout_comm,
698 				   UINT *error_code, bool check_ssl_trust, char *post_data,
699 				   WPC_RECV_CALLBACK *recv_callback, void *recv_callback_param, void *sha1_cert_hash,
700 				   bool *cancel, UINT max_recv_size, char *header_name, char *header_value)
701 {
702 	return HttpRequestEx3(data, setting, timeout_connect, timeout_comm, error_code, check_ssl_trust,
703 		post_data, recv_callback, recv_callback_param, sha1_cert_hash, (sha1_cert_hash == NULL ? 0 : 1),
704 		cancel, max_recv_size, header_name, header_value);
705 }
HttpRequestEx3(URL_DATA * data,INTERNET_SETTING * setting,UINT timeout_connect,UINT timeout_comm,UINT * error_code,bool check_ssl_trust,char * post_data,WPC_RECV_CALLBACK * recv_callback,void * recv_callback_param,void * sha1_cert_hash,UINT num_hashes,bool * cancel,UINT max_recv_size,char * header_name,char * header_value)706 BUF *HttpRequestEx3(URL_DATA *data, INTERNET_SETTING *setting,
707 					UINT timeout_connect, UINT timeout_comm,
708 					UINT *error_code, bool check_ssl_trust, char *post_data,
709 					WPC_RECV_CALLBACK *recv_callback, void *recv_callback_param, void *sha1_cert_hash, UINT num_hashes,
710 					bool *cancel, UINT max_recv_size, char *header_name, char *header_value)
711 {
712 	WPC_CONNECT con;
713 	SOCK *s;
714 	HTTP_HEADER *h;
715 	bool use_http_proxy = false;
716 	char target[MAX_SIZE * 4];
717 	char *send_str;
718 	BUF *send_buf;
719 	BUF *recv_buf;
720 	UINT http_error_code;
721 	char len_str[100];
722 	UINT content_len;
723 	void *socket_buffer;
724 	UINT socket_buffer_size = WPC_RECV_BUF_SIZE;
725 	UINT num_continue = 0;
726 	INTERNET_SETTING wt_setting;
727 	// Validate arguments
728 	if (data == NULL)
729 	{
730 		return NULL;
731 	}
732 	if (setting == NULL)
733 	{
734 		Zero(&wt_setting, sizeof(wt_setting));
735 		setting = &wt_setting;
736 	}
737 	if (error_code == NULL)
738 	{
739 		static UINT ret = 0;
740 		error_code = &ret;
741 	}
742 	if (timeout_comm == 0)
743 	{
744 		timeout_comm = WPC_TIMEOUT;
745 	}
746 	if (sha1_cert_hash == NULL)
747 	{
748 		num_hashes = 0;
749 	}
750 	if (num_hashes == 0)
751 	{
752 		sha1_cert_hash = NULL;
753 	}
754 
755 	// Connection
756 	Zero(&con, sizeof(con));
757 	StrCpy(con.HostName, sizeof(con.HostName), data->HostName);
758 	con.Port = data->Port;
759 	con.ProxyType = setting->ProxyType;
760 	StrCpy(con.ProxyHostName, sizeof(con.ProxyHostName), setting->ProxyHostName);
761 	con.ProxyPort = setting->ProxyPort;
762 	StrCpy(con.ProxyUsername, sizeof(con.ProxyUsername), setting->ProxyUsername);
763 	StrCpy(con.ProxyPassword, sizeof(con.ProxyPassword), setting->ProxyPassword);
764 
765 	if (setting->ProxyType != PROXY_HTTP || data->Secure)
766 	{
767 		use_http_proxy = false;
768 		StrCpy(target, sizeof(target), data->Target);
769 	}
770 	else
771 	{
772 		use_http_proxy = true;
773 		CreateUrl(target, sizeof(target), data);
774 	}
775 
776 	if (use_http_proxy == false)
777 	{
778 		// If the connection is not via HTTP Proxy, or is a SSL connection even via HTTP Proxy
779 		s = WpcSockConnectEx(&con, error_code, timeout_connect, cancel);
780 	}
781 	else
782 	{
783 		// If the connection is not SSL via HTTP Proxy
784 		s = TcpConnectEx3(con.ProxyHostName, con.ProxyPort, timeout_connect, cancel, NULL, true, NULL, false, false, NULL);
785 		if (s == NULL)
786 		{
787 			*error_code = ERR_PROXY_CONNECT_FAILED;
788 		}
789 	}
790 
791 	if (s == NULL)
792 	{
793 		return NULL;
794 	}
795 
796 	if (data->Secure)
797 	{
798 		// Start the SSL communication
799 		if (StartSSLEx(s, NULL, NULL, true, 0, (IsEmptyStr(data->SniString) ? NULL : data->SniString)) == false)
800 		{
801 			// SSL connection failed
802 			*error_code = ERR_PROTOCOL_ERROR;
803 			Disconnect(s);
804 			ReleaseSock(s);
805 			return NULL;
806 		}
807 
808 		if (sha1_cert_hash != NULL && num_hashes >= 1)
809 		{
810 			UCHAR hash[SHA1_SIZE];
811 			UINT i;
812 			bool ok = false;
813 
814 			Zero(hash, sizeof(hash));
815 			GetXDigest(s->RemoteX, hash, true);
816 
817 			for (i = 0;i < num_hashes;i++)
818 			{
819 				UCHAR *a = (UCHAR *)sha1_cert_hash;
820 				a += (SHA1_SIZE * i);
821 
822 				if (Cmp(hash, a, SHA1_SIZE) == 0)
823 				{
824 					ok = true;
825 					break;
826 				}
827 			}
828 
829 			if (ok == false)
830 			{
831 				// Destination certificate hash mismatch
832 				*error_code = ERR_CERT_NOT_TRUSTED;
833 				Disconnect(s);
834 				ReleaseSock(s);
835 				return NULL;
836 			}
837 		}
838 	}
839 
840 	// Timeout setting
841 	SetTimeout(s, timeout_comm);
842 
843 	// Generate a request
844 	h = NewHttpHeader(data->Method, target, use_http_proxy ? "HTTP/1.0" : "HTTP/1.1");
845 	AddHttpValue(h, NewHttpValue("Keep-Alive", HTTP_KEEP_ALIVE));
846 	AddHttpValue(h, NewHttpValue("Connection", "Keep-Alive"));
847 	AddHttpValue(h, NewHttpValue("Accept-Language", "ja"));
848 	AddHttpValue(h, NewHttpValue("User-Agent", WPC_USER_AGENT));
849 	AddHttpValue(h, NewHttpValue("Pragma", "no-cache"));
850 	AddHttpValue(h, NewHttpValue("Cache-Control", "no-cache"));
851 	AddHttpValue(h, NewHttpValue("Host", data->HeaderHostName));
852 
853 	if (IsEmptyStr(header_name) == false && IsEmptyStr(header_value) == false)
854 	{
855 		AddHttpValue(h, NewHttpValue(header_name, header_value));
856 	}
857 
858 	if (IsEmptyStr(data->Referer) == false)
859 	{
860 		AddHttpValue(h, NewHttpValue("Referer", data->Referer));
861 	}
862 
863 	if (StrCmpi(data->Method, WPC_HTTP_POST_NAME) == 0)
864 	{
865 		ToStr(len_str, StrLen(post_data));
866 		AddHttpValue(h, NewHttpValue("Content-Type", "application/x-www-form-urlencoded"));
867 		AddHttpValue(h, NewHttpValue("Content-Length", len_str));
868 	}
869 
870 	if (IsEmptyStr(data->AdditionalHeaderName) == false && IsEmptyStr(data->AdditionalHeaderValue) == false)
871 	{
872 		AddHttpValue(h, NewHttpValue(data->AdditionalHeaderName, data->AdditionalHeaderValue));
873 	}
874 
875 	if (use_http_proxy)
876 	{
877 		AddHttpValue(h, NewHttpValue("Proxy-Connection", "Keep-Alive"));
878 
879 		if (IsEmptyStr(setting->ProxyUsername) == false || IsEmptyStr(setting->ProxyPassword) == false)
880 		{
881 			char auth_tmp_str[MAX_SIZE], auth_b64_str[MAX_SIZE * 2];
882 			char basic_str[MAX_SIZE * 2];
883 
884 			// Generate the authentication string
885 			Format(auth_tmp_str, sizeof(auth_tmp_str), "%s:%s",
886 				setting->ProxyUsername, setting->ProxyPassword);
887 
888 			// Base64 encode
889 			Zero(auth_b64_str, sizeof(auth_b64_str));
890 			Encode64(auth_b64_str, auth_tmp_str);
891 			Format(basic_str, sizeof(basic_str), "Basic %s", auth_b64_str);
892 
893 			AddHttpValue(h, NewHttpValue("Proxy-Authorization", basic_str));
894 		}
895 	}
896 
897 	send_str = HttpHeaderToStr(h);
898 	FreeHttpHeader(h);
899 
900 	send_buf = NewBuf();
901 	WriteBuf(send_buf, send_str, StrLen(send_str));
902 	Free(send_str);
903 
904 	// Append to the sending data in the case of POST
905 	if (StrCmpi(data->Method, WPC_HTTP_POST_NAME) == 0)
906 	{
907 		WriteBuf(send_buf, post_data, StrLen(post_data));
908 	}
909 
910 	// Send
911 	if (SendAll(s, send_buf->Buf, send_buf->Size, s->SecureMode) == false)
912 	{
913 		Disconnect(s);
914 		ReleaseSock(s);
915 		FreeBuf(send_buf);
916 
917 		*error_code = ERR_DISCONNECTED;
918 
919 		return NULL;
920 	}
921 
922 	FreeBuf(send_buf);
923 
924 CONT:
925 	// Receive
926 	h = RecvHttpHeader(s);
927 	if (h == NULL)
928 	{
929 		Disconnect(s);
930 		ReleaseSock(s);
931 
932 		*error_code = ERR_DISCONNECTED;
933 
934 		return NULL;
935 	}
936 
937 	http_error_code = 0;
938 	if (StrLen(h->Method) == 8)
939 	{
940 		if (Cmp(h->Method, "HTTP/1.", 7) == 0)
941 		{
942 			http_error_code = ToInt(h->Target);
943 		}
944 	}
945 
946 	*error_code = ERR_NO_ERROR;
947 
948 	switch (http_error_code)
949 	{
950 	case 401:
951 	case 407:
952 		// Proxy authentication error
953 		*error_code = ERR_PROXY_AUTH_FAILED;
954 		break;
955 
956 	case 404:
957 		// 404 File Not Found
958 		*error_code = ERR_OBJECT_NOT_FOUND;
959 		break;
960 
961 	case 100:
962 		// Continue
963 		num_continue++;
964 		if (num_continue >= 10)
965 		{
966 			goto DEF;
967 		}
968 		FreeHttpHeader(h);
969 		goto CONT;
970 
971 	case 200:
972 		// Success
973 		break;
974 
975 	default:
976 		// Protocol error
977 DEF:
978 		*error_code = ERR_PROTOCOL_ERROR;
979 		break;
980 	}
981 
982 	if (*error_code != ERR_NO_ERROR)
983 	{
984 		// An error has occured
985 		Disconnect(s);
986 		ReleaseSock(s);
987 		FreeHttpHeader(h);
988 		return NULL;
989 	}
990 
991 	// Get the length of the content
992 	content_len = GetContentLength(h);
993 	if (max_recv_size != 0)
994 	{
995 		content_len = MIN(content_len, max_recv_size);
996 	}
997 
998 	FreeHttpHeader(h);
999 
1000 	socket_buffer = Malloc(socket_buffer_size);
1001 
1002 	// Receive the content
1003 	recv_buf = NewBuf();
1004 
1005 	while (true)
1006 	{
1007 		UINT recvsize = MIN(socket_buffer_size, content_len - recv_buf->Size);
1008 		UINT size;
1009 
1010 		if (recv_callback != NULL)
1011 		{
1012 			if (recv_callback(recv_callback_param,
1013 				content_len, recv_buf->Size, recv_buf) == false)
1014 			{
1015 				// Cancel the reception
1016 				*error_code = ERR_USER_CANCEL;
1017 				goto RECV_CANCEL;
1018 			}
1019 		}
1020 
1021 		if (recvsize == 0)
1022 		{
1023 			break;
1024 		}
1025 
1026 		size = Recv(s, socket_buffer, recvsize, s->SecureMode);
1027 		if (size == 0)
1028 		{
1029 			// Disconnected
1030 			*error_code = ERR_DISCONNECTED;
1031 
1032 RECV_CANCEL:
1033 			FreeBuf(recv_buf);
1034 			Free(socket_buffer);
1035 			Disconnect(s);
1036 			ReleaseSock(s);
1037 
1038 			return NULL;
1039 		}
1040 
1041 		WriteBuf(recv_buf, socket_buffer, size);
1042 	}
1043 
1044 	SeekBuf(recv_buf, 0, 0);
1045 	Free(socket_buffer);
1046 
1047 	Disconnect(s);
1048 	ReleaseSock(s);
1049 
1050 	// Transmission
1051 	return recv_buf;
1052 }
1053 
1054 // Get the proxy server settings from the registry string of IE
GetProxyServerNameAndPortFromIeProxyRegStr(char * name,UINT name_size,UINT * port,char * str,char * server_type)1055 bool GetProxyServerNameAndPortFromIeProxyRegStr(char *name, UINT name_size, UINT *port, char *str, char *server_type)
1056 {
1057 #ifdef	OS_WIN32
1058 	TOKEN_LIST *t;
1059 	UINT i;
1060 	bool ret = false;
1061 	// Validate arguments
1062 	if (name == NULL || port == NULL || str == NULL || server_type == NULL)
1063 	{
1064 		return false;
1065 	}
1066 
1067 	t = ParseToken(str, ";");
1068 
1069 	for (i = 0;i < t->NumTokens;i++)
1070 	{
1071 		char *s = t->Token[i];
1072 		UINT i;
1073 
1074 		Trim(s);
1075 
1076 		i = SearchStrEx(s, "=", 0, false);
1077 		if (i != INFINITE)
1078 		{
1079 			char tmp[MAX_PATH];
1080 
1081 			StrCpy(name, name_size, s);
1082 			name[i] = 0;
1083 
1084 			if (StrCmpi(name, server_type) == 0)
1085 			{
1086 				char *host;
1087 				StrCpy(tmp, sizeof(tmp), s + i + 1);
1088 
1089 				if (ParseHostPort(tmp, &host, port, 0))
1090 				{
1091 					StrCpy(name, name_size, host);
1092 					Free(host);
1093 
1094 					if (*port != 0)
1095 					{
1096 						ret = true;
1097 					}
1098 					break;
1099 				}
1100 			}
1101 		}
1102 	}
1103 
1104 	FreeToken(t);
1105 
1106 	return ret;
1107 #else	// OS_WIN32
1108 	return true;
1109 #endif	// OS_WIN32
1110 }
1111 
1112 // Get the internet connection settings of the system
GetSystemInternetSetting(INTERNET_SETTING * setting)1113 void GetSystemInternetSetting(INTERNET_SETTING *setting)
1114 {
1115 #ifdef	OS_WIN32
1116 	bool use_proxy;
1117 	// Validate arguments
1118 	if (setting == NULL)
1119 	{
1120 		return;
1121 	}
1122 
1123 	Zero(setting, sizeof(INTERNET_SETTING));
1124 
1125 	use_proxy = MsRegReadInt(REG_CURRENT_USER,
1126 		"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings",
1127 		"ProxyEnable");
1128 
1129 	if (use_proxy)
1130 	{
1131 		char *str = MsRegReadStr(REG_CURRENT_USER,
1132 			"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings",
1133 			"ProxyServer");
1134 		if (str != NULL)
1135 		{
1136 			char name[MAX_HOST_NAME_LEN + 1];
1137 			UINT port;
1138 
1139 			if (GetProxyServerNameAndPortFromIeProxyRegStr(name, sizeof(name),
1140 				&port, str, "https"))
1141 			{
1142 				setting->ProxyType = PROXY_HTTP;
1143 				StrCpy(setting->ProxyHostName, sizeof(setting->ProxyHostName), name);
1144 				setting->ProxyPort = port;
1145 			}
1146 			else if (GetProxyServerNameAndPortFromIeProxyRegStr(name, sizeof(name),
1147 				&port, str, "http"))
1148 			{
1149 				setting->ProxyType = PROXY_HTTP;
1150 				StrCpy(setting->ProxyHostName, sizeof(setting->ProxyHostName), name);
1151 				setting->ProxyPort = port;
1152 			}
1153 			else if (GetProxyServerNameAndPortFromIeProxyRegStr(name, sizeof(name),
1154 				&port, str, "socks"))
1155 			{
1156 				setting->ProxyType = PROXY_SOCKS;
1157 				StrCpy(setting->ProxyHostName, sizeof(setting->ProxyHostName), name);
1158 				setting->ProxyPort = port;
1159 			}
1160 			else
1161 			{
1162 				if (SearchStrEx(str, "=", 0, false) == INFINITE)
1163 				{
1164 					char *host;
1165 					UINT port;
1166 					if (ParseHostPort(str, &host, &port, 0))
1167 					{
1168 						if (port != 0)
1169 						{
1170 							setting->ProxyType = PROXY_HTTP;
1171 							StrCpy(setting->ProxyHostName, sizeof(setting->ProxyHostName), host);
1172 							setting->ProxyPort = port;
1173 						}
1174 						Free(host);
1175 					}
1176 				}
1177 			}
1178 
1179 			Free(str);
1180 		}
1181 	}
1182 #else	// OS_WIN32
1183 	Zero(setting, sizeof(INTERNET_SETTING));
1184 #endif	// OS_WIN32
1185 }
1186 
1187 // Generate the URL
CreateUrl(char * url,UINT url_size,URL_DATA * data)1188 void CreateUrl(char *url, UINT url_size, URL_DATA *data)
1189 {
1190 	char *protocol;
1191 	// Validate arguments
1192 	if (url == NULL || data == NULL)
1193 	{
1194 		return;
1195 	}
1196 
1197 	if (data->Secure == false)
1198 	{
1199 		protocol = "http://";
1200 	}
1201 	else
1202 	{
1203 		protocol = "https://";
1204 	}
1205 
1206 	Format(url, url_size, "%s%s%s", protocol, data->HeaderHostName, data->Target);
1207 }
1208 
1209 
1210 // Parse the URL
ParseUrl(URL_DATA * data,char * str,bool is_post,char * referrer)1211 bool ParseUrl(URL_DATA *data, char *str, bool is_post, char *referrer)
1212 {
1213 	char tmp[MAX_SIZE * 3];
1214 	char server_port[MAX_HOST_NAME_LEN + 16];
1215 	char *s = NULL;
1216 	char *host;
1217 	UINT port;
1218 	UINT i;
1219 	// Validate arguments
1220 	if (data == NULL || str == NULL)
1221 	{
1222 		return false;
1223 	}
1224 
1225 	Zero(data, sizeof(URL_DATA));
1226 
1227 	if (is_post)
1228 	{
1229 		StrCpy(data->Method, sizeof(data->Method), WPC_HTTP_POST_NAME);
1230 	}
1231 	else
1232 	{
1233 		StrCpy(data->Method, sizeof(data->Method), WPC_HTTP_GET_NAME);
1234 	}
1235 
1236 	if (referrer != NULL)
1237 	{
1238 		StrCpy(data->Referer, sizeof(data->Referer), referrer);
1239 	}
1240 
1241 	StrCpy(tmp, sizeof(tmp), str);
1242 	Trim(tmp);
1243 
1244 	// Determine the protocol
1245 	if (StartWith(tmp, "http://"))
1246 	{
1247 		data->Secure = false;
1248 		s = &tmp[7];
1249 	}
1250 	else if (StartWith(tmp, "https://"))
1251 	{
1252 		data->Secure = true;
1253 		s = &tmp[8];
1254 	}
1255 	else
1256 	{
1257 		if (SearchStrEx(tmp, "://", 0, false) != INFINITE)
1258 		{
1259 			return false;
1260 		}
1261 		data->Secure = false;
1262 		s = &tmp[0];
1263 	}
1264 
1265 	// Get the "server name:port number"
1266 	StrCpy(server_port, sizeof(server_port), s);
1267 	i = SearchStrEx(server_port, "/", 0, false);
1268 	if (i != INFINITE)
1269 	{
1270 		server_port[i] = 0;
1271 		s += StrLen(server_port);
1272 		StrCpy(data->Target, sizeof(data->Target), s);
1273 	}
1274 	else
1275 	{
1276 		StrCpy(data->Target, sizeof(data->Target), "/");
1277 	}
1278 
1279 	if (ParseHostPort(server_port, &host, &port, data->Secure ? 443 : 80) == false)
1280 	{
1281 		return false;
1282 	}
1283 
1284 	StrCpy(data->HostName, sizeof(data->HostName), host);
1285 	data->Port = port;
1286 
1287 	Free(host);
1288 
1289 	if ((data->Secure && data->Port == 443) || (data->Secure == false && data->Port == 80))
1290 	{
1291 		StrCpy(data->HeaderHostName, sizeof(data->HeaderHostName), data->HostName);
1292 	}
1293 	else
1294 	{
1295 		Format(data->HeaderHostName, sizeof(data->HeaderHostName),
1296 			"%s:%u", data->HostName, data->Port);
1297 	}
1298 
1299 	return true;
1300 }
1301 
1302 // String replacement
Base64ToSafe64(char * str)1303 void Base64ToSafe64(char *str)
1304 {
1305 	UINT i, len;
1306 	// Validate arguments
1307 	if (str == NULL)
1308 	{
1309 		return;
1310 	}
1311 
1312 	len = StrLen(str);
1313 
1314 	for (i = 0;i < len;i++)
1315 	{
1316 		switch (str[i])
1317 		{
1318 		case '=':
1319 			str[i] = '(';
1320 			break;
1321 
1322 		case '+':
1323 			str[i] = ')';
1324 			break;
1325 
1326 		case '/':
1327 			str[i] = '_';
1328 			break;
1329 		}
1330 	}
1331 }
Safe64ToBase64(char * str)1332 void Safe64ToBase64(char *str)
1333 {
1334 	UINT i, len;
1335 	// Validate arguments
1336 	if (str == NULL)
1337 	{
1338 		return;
1339 	}
1340 
1341 	len = StrLen(str);
1342 
1343 	for (i = 0;i < len;i++)
1344 	{
1345 		switch (str[i])
1346 		{
1347 		case '(':
1348 			str[i] = '=';
1349 			break;
1350 
1351 		case ')':
1352 			str[i] = '+';
1353 			break;
1354 
1355 		case '_':
1356 			str[i] = '/';
1357 			break;
1358 		}
1359 	}
1360 }
1361 
1362 // Decode from Safe64
DecodeSafe64(void * dst,char * src,UINT src_strlen)1363 UINT DecodeSafe64(void *dst, char *src, UINT src_strlen)
1364 {
1365 	char *tmp;
1366 	UINT ret;
1367 	if (dst == NULL || src == NULL)
1368 	{
1369 		return 0;
1370 	}
1371 
1372 	if (src_strlen == 0)
1373 	{
1374 		src_strlen = StrLen(src);
1375 	}
1376 
1377 	tmp = Malloc(src_strlen + 1);
1378 	Copy(tmp, src, src_strlen);
1379 	tmp[src_strlen] = 0;
1380 	Safe64ToBase64(tmp);
1381 
1382 	ret = B64_Decode(dst, tmp, src_strlen);
1383 	Free(tmp);
1384 
1385 	return ret;
1386 }
1387 
1388 // Encode to Safe64
EncodeSafe64(char * dst,void * src,UINT src_size)1389 void EncodeSafe64(char *dst, void *src, UINT src_size)
1390 {
1391 	UINT size;
1392 	if (dst == NULL || src == NULL)
1393 	{
1394 		return;
1395 	}
1396 
1397 	size = B64_Encode(dst, src, src_size);
1398 	dst[size] = 0;
1399 
1400 	Base64ToSafe64(dst);
1401 }
1402 
1403