// SoftEther VPN Source Code - Developer Edition Master Branch // Cedar Communication Module // Wpc.c // RPC over HTTP #include "Wpc.h" #include "Command.h" #include "Protocol.h" #include "Mayaqua/DNS.h" #include "Mayaqua/Encoding.h" #include "Mayaqua/Memory.h" #include "Mayaqua/Microsoft.h" #include "Mayaqua/Pack.h" #include "Mayaqua/Proxy.h" #include "Mayaqua/Str.h" // Get whether the proxy server is specified by a private IP bool IsProxyPrivateIp(INTERNET_SETTING *s) { IP ip; // Validate arguments if (s == NULL) { return false; } if (s->ProxyType == PROXY_DIRECT) { return false; } if (GetIP(&ip, s->ProxyHostName) == false) { return false; } if (IsIPPrivate(&ip)) { return true; } if (IsIPMyHost(&ip)) { return true; } if (IsLocalHostIP(&ip)) { return true; } return false; } // Call PACK *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) { return WpcCallEx(url, setting, timeout_connect, timeout_comm, function_name, pack, cert, key, sha1_cert_hash, NULL, 0, NULL, NULL); } PACK *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) { return WpcCallEx2(url, setting, timeout_connect, timeout_comm, function_name, pack, cert, key, sha1_cert_hash, (sha1_cert_hash == NULL ? 0 : 1), cancel, max_recv_size, additional_header_name, additional_header_value, NULL); } PACK *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) { URL_DATA data; BUF *b, *recv; UINT error; WPC_PACKET packet; // Validate arguments if (function_name == NULL || pack == NULL) { return PackError(ERR_INTERNAL_ERROR); } if (ParseUrl(&data, url, true, NULL) == false) { return PackError(ERR_INTERNAL_ERROR); } PackAddStr(pack, "function", function_name); b = WpcGeneratePacket(pack, cert, key); if (b == NULL) { return PackError(ERR_INTERNAL_ERROR); } SeekBuf(b, b->Size, 0); WriteBufInt(b, 0); SeekBuf(b, 0, 0); if (IsEmptyStr(additional_header_name) == false && IsEmptyStr(additional_header_value) == false) { StrCpy(data.AdditionalHeaderName, sizeof(data.AdditionalHeaderName), additional_header_name); StrCpy(data.AdditionalHeaderValue, sizeof(data.AdditionalHeaderValue), additional_header_value); } if (sni_string != NULL && IsEmptyStr(sni_string) == false) { StrCpy(data.SniString, sizeof(data.SniString), sni_string); } recv = HttpRequestEx3(&data, setting, timeout_connect, timeout_comm, &error, false, b->Buf, NULL, NULL, sha1_cert_hash, num_hashes, cancel, max_recv_size, NULL, NULL); FreeBuf(b); if (recv == NULL) { return PackError(error); } if (WpcParsePacket(&packet, recv) == false) { FreeBuf(recv); return PackError(ERR_PROTOCOL_ERROR); } FreeBuf(recv); FreeX(packet.Cert); return packet.Pack; } // Release the packet void WpcFreePacket(WPC_PACKET *packet) { // Validate arguments if (packet == NULL) { return; } FreePack(packet->Pack); FreeX(packet->Cert); } // Parse the packet bool WpcParsePacket(WPC_PACKET *packet, BUF *buf) { LIST *o; BUF *b; bool ret = false; UCHAR hash[SHA1_SIZE]; // Validate arguments if (packet == NULL || buf == NULL) { return false; } Zero(packet, sizeof(WPC_PACKET)); o = WpcParseDataEntry(buf); b = WpcDataEntryToBuf(WpcFindDataEntry(o, "PACK")); if (b != NULL) { Sha1(hash, b->Buf, b->Size); packet->Pack = BufToPack(b); FreeBuf(b); if (packet->Pack != NULL) { BUF *b; ret = true; b = WpcDataEntryToBuf(WpcFindDataEntry(o, "HASH")); if (b != NULL) { if (b->Size != SHA1_SIZE || Cmp(b->Buf, hash, SHA1_SIZE) != 0) { ret = false; FreePack(packet->Pack); } else { BUF *b; Copy(packet->Hash, hash, SHA1_SIZE); b = WpcDataEntryToBuf(WpcFindDataEntry(o, "CERT")); if (b != NULL) { X *cert = BufToX(b, false); if (cert == NULL) { ret = false; FreePack(packet->Pack); } else { BUF *b = WpcDataEntryToBuf(WpcFindDataEntry(o, "SIGN")); if (b == NULL || (b->Size != 128)) { ret = false; FreeX(cert); FreePack(packet->Pack); } else { K *k = GetKFromX(cert); if (RsaVerify(hash, SHA1_SIZE, b->Buf, k) == false) { ret = false; FreeX(cert); FreePack(packet->Pack); } else { packet->Cert = cert; Copy(packet->Sign, b->Buf, 128); } FreeK(k); } FreeBuf(b); } FreeBuf(b); } } FreeBuf(b); } } } WpcFreeDataEntryList(o); return ret; } // Generate the packet BUF *WpcGeneratePacket(PACK *pack, X *cert, K *key) { UCHAR hash[SHA1_SIZE]; BUF *pack_data; BUF *cert_data = NULL; BUF *sign_data = NULL; BUF *b; // Validate arguments if (pack == NULL) { return NULL; } pack_data = PackToBuf(pack); Sha1(hash, pack_data->Buf, pack_data->Size); if (cert != NULL && key != NULL) { UCHAR sign[128]; cert_data = XToBuf(cert, false); RsaSign(sign, hash, sizeof(hash), key); sign_data = NewBuf(); WriteBuf(sign_data, sign, sizeof(sign)); SeekBuf(sign_data, 0, 0); } b = NewBuf(); WpcAddDataEntryBin(b, "PACK", pack_data->Buf, pack_data->Size); WpcAddDataEntryBin(b, "HASH", hash, sizeof(hash)); if (cert_data != NULL) { WpcAddDataEntryBin(b, "CERT", cert_data->Buf, cert_data->Size); WpcAddDataEntryBin(b, "SIGN", sign_data->Buf, sign_data->Size); } FreeBuf(pack_data); FreeBuf(cert_data); FreeBuf(sign_data); SeekBuf(b, 0, 0); return b; } // Decode the buffer from WPC_ENTRY BUF *WpcDataEntryToBuf(WPC_ENTRY *e) { void *data; UINT data_size; UINT size; BUF *b; // Validate arguments if (e == NULL) { return NULL; } data_size = e->Size + 4096; data = Malloc(data_size); size = DecodeSafe64(data, e->Data, e->Size); b = NewBuf(); WriteBuf(b, data, size); SeekBuf(b, 0, 0); Free(data); return b; } // Search for the data entry WPC_ENTRY *WpcFindDataEntry(LIST *o, char *name) { UINT i; char name_str[WPC_DATA_ENTRY_SIZE]; // Validate arguments if (o == NULL || name == NULL) { return NULL; } WpcFillEntryName(name_str, name); for (i = 0;i < LIST_NUM(o);i++) { WPC_ENTRY *e = LIST_DATA(o, i); if (Cmp(e->EntryName, name_str, WPC_DATA_ENTRY_SIZE) == 0) { return e; } } return NULL; } // Release the data entry list void WpcFreeDataEntryList(LIST *o) { UINT i; // Validate arguments if (o == NULL) { return; } for (i = 0;i < LIST_NUM(o);i++) { WPC_ENTRY *e = LIST_DATA(o, i); Free(e); } ReleaseList(o); } // Parse the data entry LIST *WpcParseDataEntry(BUF *b) { char entry_name[WPC_DATA_ENTRY_SIZE]; char size_str[11]; LIST *o; // Validate arguments if (b == NULL) { return NULL; } SeekBuf(b, 0, 0); o = NewListFast(NULL); while (true) { UINT size; WPC_ENTRY *e; if (ReadBuf(b, entry_name, WPC_DATA_ENTRY_SIZE) != WPC_DATA_ENTRY_SIZE) { break; } Zero(size_str, sizeof(size_str)); if (ReadBuf(b, size_str, 10) != 10) { break; } size = ToInt(size_str); if ((b->Size - b->Current) < size) { break; } e = ZeroMalloc(sizeof(WPC_ENTRY)); e->Data = (UCHAR *)b->Buf + b->Current; Copy(e->EntryName, entry_name, WPC_DATA_ENTRY_SIZE); e->Size = size; SeekBuf(b, size, 1); Add(o, e); } return o; } // Generate a entry name void WpcFillEntryName(char *dst, char *name) { UINT i, len; char tmp[MAX_SIZE]; // Validate arguments if (dst == NULL || name == NULL) { return; } StrCpy(tmp, sizeof(tmp), name); StrUpper(tmp); len = StrLen(tmp); for (i = 0;i < WPC_DATA_ENTRY_SIZE;i++) { dst[i] = ' '; } if (len <= WPC_DATA_ENTRY_SIZE) { Copy(dst, tmp, len); } else { Copy(dst, tmp, WPC_DATA_ENTRY_SIZE); } } // Add the data entry (binary) void WpcAddDataEntryBin(BUF *b, char *name, void *data, UINT size) { char *str; // Validate arguments if (b == NULL || name == NULL || (data == NULL && size != 0)) { return; } str = Malloc(size * 2 + 64); EncodeSafe64(str, data, size); WpcAddDataEntry(b, name, str, StrLen(str)); Free(str); } // Add the data entry void WpcAddDataEntry(BUF *b, char *name, void *data, UINT size) { char entry_name[WPC_DATA_ENTRY_SIZE]; char size_str[11]; // Validate arguments if (b == NULL || name == NULL || (data == NULL && size != 0)) { return; } WpcFillEntryName(entry_name, name); WriteBuf(b, entry_name, WPC_DATA_ENTRY_SIZE); Format(size_str, sizeof(size_str), "%010u", size); WriteBuf(b, size_str, 10); WriteBuf(b, data, size); } // Get the empty INTERNET_SETTING INTERNET_SETTING *GetNullInternetSetting() { static INTERNET_SETTING ret; Zero(&ret, sizeof(ret)); return &ret; } // Socket connection SOCK *WpcSockConnect(WPC_CONNECT *param, UINT *error_code, UINT timeout) { return WpcSockConnectEx(param, error_code, timeout, NULL); } SOCK *WpcSockConnectEx(WPC_CONNECT *param, UINT *error_code, UINT timeout, bool *cancel) { SOCK *sock; UINT ret; // Validate arguments if (param == NULL) { return NULL; } if (error_code == NULL) { error_code = &ret; } if (param->ProxyType == PROXY_DIRECT) { sock = TcpConnectEx3(param->HostName, param->Port, timeout, cancel, NULL, true, NULL, false, NULL); *error_code = (sock != NULL ? ERR_NO_ERROR : ERR_CONNECT_FAILED); return sock; } else { PROXY_PARAM_OUT out; PROXY_PARAM_IN in; UINT ret; Zero(&in, sizeof(in)); in.Timeout = timeout; StrCpy(in.TargetHostname, sizeof(in.TargetHostname), param->HostName); in.TargetPort = param->Port; StrCpy(in.Hostname, sizeof(in.Hostname), param->ProxyHostName); in.Port = param->ProxyPort; StrCpy(in.Username, sizeof(in.Username), param->ProxyUsername); StrCpy(in.Password, sizeof(in.Password), param->ProxyPassword); StrCpy(in.HttpCustomHeader, sizeof(in.HttpCustomHeader), param->CustomHttpHeader); switch (param->ProxyType) { case PROXY_HTTP: ret = ProxyHttpConnect(&out, &in, cancel); break; case PROXY_SOCKS: ret = ProxySocks4Connect(&out, &in, cancel); break; case PROXY_SOCKS5: ret = ProxySocks5Connect(&out, &in, cancel); break; default: *error_code = ERR_INTERNAL_ERROR; Debug("WpcSockConnect(): Unknown proxy type: %u!\n", param->ProxyType); return NULL; } *error_code = ProxyCodeToCedar(ret); if (*error_code != ERR_NO_ERROR) { Debug("ClientConnectGetSocket(): Connection via proxy server failed with error %u\n", ret); return NULL; } return out.Sock; } } SOCK *WpcSockConnect2(char *hostname, UINT port, INTERNET_SETTING *t, UINT *error_code, UINT timeout) { // Validate arguments INTERNET_SETTING t2; WPC_CONNECT c; if (t == NULL) { Zero(&t2, sizeof(t2)); t = &t2; } Zero(&c, sizeof(c)); StrCpy(c.HostName, sizeof(c.HostName), hostname); c.Port = port; c.ProxyType = t->ProxyType; StrCpy(c.ProxyHostName, sizeof(c.HostName), t->ProxyHostName); c.ProxyPort = t->ProxyPort; StrCpy(c.ProxyUsername, sizeof(c.ProxyUsername), t->ProxyUsername); StrCpy(c.ProxyPassword, sizeof(c.ProxyPassword), t->ProxyPassword); StrCpy(c.CustomHttpHeader, sizeof(c.CustomHttpHeader), t->CustomHttpHeader); return WpcSockConnect(&c, error_code, timeout); } // Handle the HTTP request BUF *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) { return HttpRequestEx(data, setting, timeout_connect, timeout_comm, error_code, check_ssl_trust, post_data, recv_callback, recv_callback_param, sha1_cert_hash, NULL, 0); } BUF *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) { return HttpRequestEx2(data, setting, timeout_connect, timeout_comm, error_code, check_ssl_trust, post_data, recv_callback, recv_callback_param, sha1_cert_hash, cancel, max_recv_size, NULL, NULL); } BUF *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) { return HttpRequestEx3(data, setting, timeout_connect, timeout_comm, error_code, check_ssl_trust, post_data, recv_callback, recv_callback_param, sha1_cert_hash, (sha1_cert_hash == NULL ? 0 : 1), cancel, max_recv_size, header_name, header_value); } BUF *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) { WPC_CONNECT con; SOCK *s; HTTP_HEADER *h; bool use_http_proxy = false; char target[MAX_SIZE * 4]; char *send_str; BUF *send_buf; BUF *recv_buf; UINT http_error_code; char len_str[100]; UINT content_len; void *socket_buffer; UINT socket_buffer_size = WPC_RECV_BUF_SIZE; UINT num_continue = 0; INTERNET_SETTING wt_setting; // Validate arguments if (data == NULL) { return NULL; } if (setting == NULL) { Zero(&wt_setting, sizeof(wt_setting)); setting = &wt_setting; } if (error_code == NULL) { static UINT ret = 0; error_code = &ret; } if (timeout_comm == 0) { timeout_comm = WPC_TIMEOUT; } if (sha1_cert_hash == NULL) { num_hashes = 0; } if (num_hashes == 0) { sha1_cert_hash = NULL; } // Connection Zero(&con, sizeof(con)); StrCpy(con.HostName, sizeof(con.HostName), data->HostName); con.Port = data->Port; con.ProxyType = setting->ProxyType; StrCpy(con.ProxyHostName, sizeof(con.ProxyHostName), setting->ProxyHostName); con.ProxyPort = setting->ProxyPort; StrCpy(con.ProxyUsername, sizeof(con.ProxyUsername), setting->ProxyUsername); StrCpy(con.ProxyPassword, sizeof(con.ProxyPassword), setting->ProxyPassword); StrCpy(con.CustomHttpHeader, sizeof(con.CustomHttpHeader), setting->CustomHttpHeader); if (setting->ProxyType != PROXY_HTTP || data->Secure) { use_http_proxy = false; StrCpy(target, sizeof(target), data->Target); } else { use_http_proxy = true; CreateUrl(target, sizeof(target), data); } if (use_http_proxy == false) { // If the connection is not via HTTP Proxy, or is a SSL connection even via HTTP Proxy s = WpcSockConnectEx(&con, error_code, timeout_connect, cancel); } else { // If the connection is not SSL via HTTP Proxy s = TcpConnectEx3(con.ProxyHostName, con.ProxyPort, timeout_connect, cancel, NULL, true, NULL, false, NULL); if (s == NULL) { *error_code = ERR_PROXY_CONNECT_FAILED; } } if (s == NULL) { return NULL; } if (data->Secure) { // Start the SSL communication if (StartSSLEx(s, NULL, NULL, 0, (IsEmptyStr(data->SniString) ? NULL : data->SniString)) == false) { // SSL connection failed *error_code = ERR_PROTOCOL_ERROR; Disconnect(s); ReleaseSock(s); return NULL; } if (sha1_cert_hash != NULL && num_hashes >= 1) { UCHAR hash[SHA1_SIZE]; UINT i; bool ok = false; Zero(hash, sizeof(hash)); GetXDigest(s->RemoteX, hash, true); for (i = 0;i < num_hashes;i++) { UCHAR *a = (UCHAR *)sha1_cert_hash; a += (SHA1_SIZE * i); if (Cmp(hash, a, SHA1_SIZE) == 0) { ok = true; break; } } if (ok == false) { // Destination certificate hash mismatch *error_code = ERR_CERT_NOT_TRUSTED; Disconnect(s); ReleaseSock(s); return NULL; } } } // Timeout setting SetTimeout(s, timeout_comm); // Generate a request h = NewHttpHeader(data->Method, target, use_http_proxy ? "HTTP/1.0" : "HTTP/1.1"); AddHttpValue(h, NewHttpValue("Keep-Alive", HTTP_KEEP_ALIVE)); AddHttpValue(h, NewHttpValue("Connection", "Keep-Alive")); AddHttpValue(h, NewHttpValue("Accept-Language", "ja")); AddHttpValue(h, NewHttpValue("User-Agent", WPC_USER_AGENT)); AddHttpValue(h, NewHttpValue("Pragma", "no-cache")); AddHttpValue(h, NewHttpValue("Cache-Control", "no-cache")); AddHttpValue(h, NewHttpValue("Host", data->HeaderHostName)); if (IsEmptyStr(header_name) == false && IsEmptyStr(header_value) == false) { AddHttpValue(h, NewHttpValue(header_name, header_value)); } if (IsEmptyStr(data->Referer) == false) { AddHttpValue(h, NewHttpValue("Referer", data->Referer)); } if (StrCmpi(data->Method, WPC_HTTP_POST_NAME) == 0) { ToStr(len_str, StrLen(post_data)); AddHttpValue(h, NewHttpValue("Content-Type", "application/x-www-form-urlencoded")); AddHttpValue(h, NewHttpValue("Content-Length", len_str)); } if (IsEmptyStr(data->AdditionalHeaderName) == false && IsEmptyStr(data->AdditionalHeaderValue) == false) { AddHttpValue(h, NewHttpValue(data->AdditionalHeaderName, data->AdditionalHeaderValue)); } if (use_http_proxy) { AddHttpValue(h, NewHttpValue("Proxy-Connection", "Keep-Alive")); if (IsEmptyStr(setting->ProxyUsername) == false || IsEmptyStr(setting->ProxyPassword) == false) { char auth_str[MAX_SIZE * 2]; Format(auth_str, sizeof(auth_str), "%s:%s", setting->ProxyUsername, setting->ProxyPassword); char *base64 = Base64FromBin(NULL, auth_str, StrLen(auth_str)); Format(auth_str, sizeof(auth_str), "Basic %s", base64); Free(base64); AddHttpValue(h, NewHttpValue("Proxy-Authorization", auth_str)); } } send_str = HttpHeaderToStr(h); FreeHttpHeader(h); send_buf = NewBuf(); WriteBuf(send_buf, send_str, StrLen(send_str)); Free(send_str); // Append to the sending data in the case of POST if (StrCmpi(data->Method, WPC_HTTP_POST_NAME) == 0) { WriteBuf(send_buf, post_data, StrLen(post_data)); } // Send if (SendAll(s, send_buf->Buf, send_buf->Size, s->SecureMode) == false) { Disconnect(s); ReleaseSock(s); FreeBuf(send_buf); *error_code = ERR_DISCONNECTED; return NULL; } FreeBuf(send_buf); CONT: // Receive h = RecvHttpHeader(s); if (h == NULL) { Disconnect(s); ReleaseSock(s); *error_code = ERR_DISCONNECTED; return NULL; } http_error_code = 0; if (StrLen(h->Method) == 8) { if (Cmp(h->Method, "HTTP/1.", 7) == 0) { http_error_code = ToInt(h->Target); } } *error_code = ERR_NO_ERROR; switch (http_error_code) { case 401: case 407: // Proxy authentication error *error_code = ERR_PROXY_AUTH_FAILED; break; case 404: // 404 File Not Found *error_code = ERR_OBJECT_NOT_FOUND; break; case 100: // Continue num_continue++; if (num_continue >= 10) { goto DEF; } FreeHttpHeader(h); goto CONT; case 200: // Success break; default: // Protocol error DEF: *error_code = ERR_PROTOCOL_ERROR; break; } if (*error_code != ERR_NO_ERROR) { // An error has occured Disconnect(s); ReleaseSock(s); FreeHttpHeader(h); return NULL; } // Get the length of the content content_len = GetContentLength(h); if (max_recv_size != 0) { content_len = MIN(content_len, max_recv_size); } FreeHttpHeader(h); socket_buffer = Malloc(socket_buffer_size); // Receive the content recv_buf = NewBuf(); while (true) { UINT recvsize = MIN(socket_buffer_size, content_len - recv_buf->Size); UINT size; if (recv_callback != NULL) { if (recv_callback(recv_callback_param, content_len, recv_buf->Size, recv_buf) == false) { // Cancel the reception *error_code = ERR_USER_CANCEL; goto RECV_CANCEL; } } if (recvsize == 0) { break; } size = Recv(s, socket_buffer, recvsize, s->SecureMode); if (size == 0) { // Disconnected *error_code = ERR_DISCONNECTED; RECV_CANCEL: FreeBuf(recv_buf); Free(socket_buffer); Disconnect(s); ReleaseSock(s); return NULL; } WriteBuf(recv_buf, socket_buffer, size); } SeekBuf(recv_buf, 0, 0); Free(socket_buffer); Disconnect(s); ReleaseSock(s); // Transmission return recv_buf; } // Get the proxy server settings from the registry string of IE bool GetProxyServerNameAndPortFromIeProxyRegStr(char *name, UINT name_size, UINT *port, char *str, char *server_type) { #ifdef OS_WIN32 TOKEN_LIST *t; UINT i; bool ret = false; // Validate arguments if (name == NULL || port == NULL || str == NULL || server_type == NULL) { return false; } t = ParseToken(str, ";"); for (i = 0;i < t->NumTokens;i++) { char *s = t->Token[i]; UINT i; Trim(s); i = SearchStrEx(s, "=", 0, false); if (i != INFINITE) { char tmp[MAX_PATH]; StrCpy(name, name_size, s); name[i] = 0; if (StrCmpi(name, server_type) == 0) { char *host; StrCpy(tmp, sizeof(tmp), s + i + 1); if (ParseHostPort(tmp, &host, port, 0)) { StrCpy(name, name_size, host); Free(host); if (*port != 0) { ret = true; } break; } } } } FreeToken(t); return ret; #else // OS_WIN32 return true; #endif // OS_WIN32 } // Get the internet connection settings of the system void GetSystemInternetSetting(INTERNET_SETTING *setting) { #ifdef OS_WIN32 bool use_proxy; // Validate arguments if (setting == NULL) { return; } Zero(setting, sizeof(INTERNET_SETTING)); use_proxy = MsRegReadInt(REG_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", "ProxyEnable"); if (use_proxy) { char *str = MsRegReadStr(REG_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", "ProxyServer"); if (str != NULL) { char name[MAX_HOST_NAME_LEN + 1]; UINT port; if (GetProxyServerNameAndPortFromIeProxyRegStr(name, sizeof(name), &port, str, "https")) { setting->ProxyType = PROXY_HTTP; StrCpy(setting->ProxyHostName, sizeof(setting->ProxyHostName), name); setting->ProxyPort = port; } else if (GetProxyServerNameAndPortFromIeProxyRegStr(name, sizeof(name), &port, str, "http")) { setting->ProxyType = PROXY_HTTP; StrCpy(setting->ProxyHostName, sizeof(setting->ProxyHostName), name); setting->ProxyPort = port; } else if (GetProxyServerNameAndPortFromIeProxyRegStr(name, sizeof(name), &port, str, "socks")) { setting->ProxyType = PROXY_SOCKS; StrCpy(setting->ProxyHostName, sizeof(setting->ProxyHostName), name); setting->ProxyPort = port; } else { if (SearchStrEx(str, "=", 0, false) == INFINITE) { char *host; UINT port; if (ParseHostPort(str, &host, &port, 0)) { if (port != 0) { setting->ProxyType = PROXY_HTTP; StrCpy(setting->ProxyHostName, sizeof(setting->ProxyHostName), host); setting->ProxyPort = port; } Free(host); } } } Free(str); } } #else // OS_WIN32 Zero(setting, sizeof(INTERNET_SETTING)); #endif // OS_WIN32 } // Generate the URL void CreateUrl(char *url, UINT url_size, URL_DATA *data) { char *protocol; // Validate arguments if (url == NULL || data == NULL) { return; } if (data->Secure == false) { protocol = "http://"; } else { protocol = "https://"; } Format(url, url_size, "%s%s%s", protocol, data->HeaderHostName, data->Target); } // Parse the URL bool ParseUrl(URL_DATA *data, char *str, bool is_post, char *referrer) { char tmp[MAX_SIZE * 3]; char server_port[MAX_HOST_NAME_LEN + 16]; char *s = NULL; char *host; UINT port; UINT i; // Validate arguments if (data == NULL || str == NULL) { return false; } Zero(data, sizeof(URL_DATA)); if (is_post) { StrCpy(data->Method, sizeof(data->Method), WPC_HTTP_POST_NAME); } else { StrCpy(data->Method, sizeof(data->Method), WPC_HTTP_GET_NAME); } if (referrer != NULL) { StrCpy(data->Referer, sizeof(data->Referer), referrer); } StrCpy(tmp, sizeof(tmp), str); Trim(tmp); // Determine the protocol if (StartWith(tmp, "http://")) { data->Secure = false; s = &tmp[7]; } else if (StartWith(tmp, "https://")) { data->Secure = true; s = &tmp[8]; } else { if (SearchStrEx(tmp, "://", 0, false) != INFINITE) { return false; } data->Secure = false; s = &tmp[0]; } // Get the "server name:port number" StrCpy(server_port, sizeof(server_port), s); i = SearchStrEx(server_port, "/", 0, false); if (i != INFINITE) { server_port[i] = 0; s += StrLen(server_port); StrCpy(data->Target, sizeof(data->Target), s); } else { StrCpy(data->Target, sizeof(data->Target), "/"); } if (ParseHostPort(server_port, &host, &port, data->Secure ? 443 : 80) == false) { return false; } StrCpy(data->HostName, sizeof(data->HostName), host); data->Port = port; Free(host); if ((data->Secure && data->Port == 443) || (data->Secure == false && data->Port == 80)) { StrCpy(data->HeaderHostName, sizeof(data->HeaderHostName), data->HostName); } else { Format(data->HeaderHostName, sizeof(data->HeaderHostName), "%s:%u", data->HostName, data->Port); } return true; } // String replacement void Base64ToSafe64(char *str, const UINT size) { if (str == NULL || size == 0) { return; } for (UINT i = 0; i < size; ++i) { switch (str[i]) { case '=': str[i] = '('; break; case '+': str[i] = ')'; break; case '/': str[i] = '_'; break; } } } void Safe64ToBase64(char *str, const UINT size) { if (str == NULL || size == 0) { return; } for (UINT i = 0; i < size; ++i) { switch (str[i]) { case '(': str[i] = '='; break; case ')': str[i] = '+'; break; case '_': str[i] = '/'; break; } } } // Decode from escaped Base64 UINT DecodeSafe64(void *dst, const char *src, UINT size) { if (dst == NULL || src == NULL) { return 0; } if (size == 0) { size = StrLen(src); } char *tmp = Malloc(size + 1); Copy(tmp, src, size); tmp[size] = '\0'; Safe64ToBase64(tmp, size); const UINT ret = Base64Decode(dst, tmp, size); Free(tmp); return ret; } // Encode to escaped Base64 void EncodeSafe64(char *dst, const void *src, const UINT size) { if (dst == NULL || src == NULL) { return; } const UINT ret = Base64Encode(dst, src, size); Base64ToSafe64(dst, ret); }