SOAPSock.cpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. /*
  2. * Copyright 2005 - 2016 Zarafa and its licensors
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU Affero General Public License, version 3,
  6. * as published by the Free Software Foundation.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU Affero General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU Affero General Public License
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. *
  16. */
  17. #include <kopano/platform.h>
  18. #include <memory>
  19. #include "SOAPSock.h"
  20. #include <sys/un.h>
  21. #include "SOAPUtils.h"
  22. #include <kopano/ECLogger.h>
  23. #include <kopano/stringutil.h>
  24. #include <kopano/CommonUtil.h>
  25. #include <string>
  26. #include <map>
  27. #include <kopano/charset/convert.h>
  28. #include <kopano/charset/utf8string.h>
  29. using namespace std;
  30. // we cannot patch http_post now (see external/gsoap/*.diff), so we redefine it
  31. static int
  32. http_post(struct soap *soap, const char *endpoint, const char *host, int port, const char *path, const char *action, size_t count)
  33. { int err;
  34. if (strlen(endpoint) + strlen(soap->http_version) > sizeof(soap->tmpbuf) - 80
  35. || strlen(host) + strlen(soap->http_version) > sizeof(soap->tmpbuf) - 80)
  36. return soap->error = SOAP_EOM;
  37. sprintf(soap->tmpbuf, "POST /%s HTTP/%s", (*path == '/' ? path + 1 : path), soap->http_version);
  38. if ((err = soap->fposthdr(soap, soap->tmpbuf, NULL)) ||
  39. (err = soap->fposthdr(soap, "Host", host)) ||
  40. (err = soap->fposthdr(soap, "User-Agent", "gSOAP/2.8")) ||
  41. (err = soap_puthttphdr(soap, SOAP_OK, count)))
  42. return err;
  43. #ifdef WITH_ZLIB
  44. #ifdef WITH_GZIP
  45. if ((err = soap->fposthdr(soap, "Accept-Encoding", "gzip, deflate")))
  46. #else
  47. if ((err = soap->fposthdr(soap, "Accept-Encoding", "deflate")))
  48. #endif
  49. return err;
  50. #endif
  51. return soap->fposthdr(soap, NULL, NULL);
  52. }
  53. // This function wraps the GSOAP fopen call to support "file:///var/run/socket" Unix socket URIs
  54. static int gsoap_connect_pipe(struct soap *soap, const char *endpoint,
  55. const char *host, int port)
  56. {
  57. int fd;
  58. struct sockaddr_un saddr;
  59. memset(&saddr, 0, sizeof(struct sockaddr_un));
  60. // See stdsoap2.cpp:tcp_connect() function
  61. if (soap_valid_socket(soap->socket))
  62. return SOAP_OK;
  63. soap->socket = SOAP_INVALID_SOCKET;
  64. if (strncmp(endpoint, "file://", 7) != 0)
  65. return SOAP_EOF;
  66. const char *socket_name = strchr(endpoint + 7, '/');
  67. // >= because there also needs to be room for the 0x00
  68. if (socket_name == NULL ||
  69. strlen(socket_name) >= sizeof(saddr.sun_path))
  70. return SOAP_EOF;
  71. fd = socket(PF_UNIX, SOCK_STREAM, 0);
  72. if (fd < 0)
  73. return SOAP_EOF;
  74. saddr.sun_family = AF_UNIX;
  75. kc_strlcpy(saddr.sun_path, socket_name, sizeof(saddr.sun_path));
  76. if (connect(fd, (struct sockaddr *)&saddr, sizeof(struct sockaddr_un)) < 0) {
  77. close(fd);
  78. return SOAP_EOF;
  79. }
  80. soap->sendfd = soap->recvfd = SOAP_INVALID_SOCKET;
  81. soap->socket = fd;
  82. // Because 'file:///var/run/file' will be parsed into host='', path='/var/run/file',
  83. // the gSOAP code doesn't set the soap->status variable. (see soap_connect_command in
  84. // stdsoap2.cpp:12278) This could possibly lead to
  85. // soap->status accidentally being set to SOAP_GET, which would break things. The
  86. // chances of this happening are, of course, small, but also very real.
  87. soap->status = SOAP_POST;
  88. return SOAP_OK;
  89. }
  90. HRESULT CreateSoapTransport(ULONG ulUIFlags,
  91. const char *strServerPath,
  92. const char *strSSLKeyFile,
  93. const char *strSSLKeyPass,
  94. ULONG ulConnectionTimeOut,
  95. const char *strProxyHost,
  96. WORD wProxyPort,
  97. const char *strProxyUserName,
  98. const char *strProxyPassword,
  99. ULONG ulProxyFlags,
  100. int iSoapiMode,
  101. int iSoapoMode,
  102. KCmd **lppCmd)
  103. {
  104. KCmd* lpCmd = NULL;
  105. if (strServerPath == NULL || *strServerPath == '\0' || lppCmd == NULL)
  106. return E_INVALIDARG;
  107. lpCmd = new KCmd();
  108. soap_set_imode(lpCmd->soap, iSoapiMode);
  109. soap_set_omode(lpCmd->soap, iSoapoMode);
  110. lpCmd->endpoint = strdup(strServerPath);
  111. lpCmd->soap->sndbuf = lpCmd->soap->rcvbuf = 0;
  112. // default allow SSLv3, TLSv1, TLSv1.1 and TLSv1.2
  113. lpCmd->soap->ctx = SSL_CTX_new(SSLv23_method());
  114. #ifdef WITH_OPENSSL
  115. if (strncmp("https:", lpCmd->endpoint, 6) == 0) {
  116. // no need to add certificates to call, since soap also calls SSL_CTX_set_default_verify_paths()
  117. if (soap_ssl_client_context(lpCmd->soap, SOAP_SSL_DEFAULT,
  118. strSSLKeyFile != NULL && *strSSLKeyFile != '\0' ? strSSLKeyFile : NULL,
  119. strSSLKeyPass != NULL && *strSSLKeyPass != '\0' ? strSSLKeyPass : NULL,
  120. NULL, NULL,
  121. NULL)) {
  122. free(const_cast<char *>(lpCmd->endpoint));
  123. delete lpCmd;
  124. return E_INVALIDARG;
  125. }
  126. // set our own certificate check function
  127. lpCmd->soap->fsslverify = ssl_verify_callback_kopano_silent;
  128. SSL_CTX_set_verify(lpCmd->soap->ctx, SSL_VERIFY_PEER, lpCmd->soap->fsslverify);
  129. }
  130. #endif
  131. if(strncmp("file:", lpCmd->endpoint, 5) == 0) {
  132. lpCmd->soap->fconnect = gsoap_connect_pipe;
  133. lpCmd->soap->fpost = http_post;
  134. } else {
  135. if ((ulProxyFlags&0x0000001/*EC_PROFILE_PROXY_FLAGS_USE_PROXY*/) && strProxyHost != NULL && *strProxyHost != '\0') {
  136. lpCmd->soap->proxy_host = strdup(strProxyHost);
  137. lpCmd->soap->proxy_port = wProxyPort;
  138. if (strProxyUserName != NULL && *strProxyUserName != '\0')
  139. lpCmd->soap->proxy_userid = strdup(strProxyUserName);
  140. if (strProxyPassword != NULL && *strProxyPassword != '\0')
  141. lpCmd->soap->proxy_passwd = strdup(strProxyPassword);
  142. }
  143. lpCmd->soap->connect_timeout = ulConnectionTimeOut;
  144. }
  145. *lppCmd = lpCmd;
  146. return hrSuccess;
  147. }
  148. VOID DestroySoapTransport(KCmd *lpCmd)
  149. {
  150. if (!lpCmd)
  151. return;
  152. /* strdup'd all of them earlier */
  153. free(const_cast<char *>(lpCmd->endpoint));
  154. free(const_cast<char *>(lpCmd->soap->proxy_host));
  155. free(const_cast<char *>(lpCmd->soap->proxy_userid));
  156. free(const_cast<char *>(lpCmd->soap->proxy_passwd));
  157. delete lpCmd;
  158. }
  159. int ssl_verify_callback_kopano_silent(int ok, X509_STORE_CTX *store)
  160. {
  161. int sslerr;
  162. if (ok == 0)
  163. {
  164. // Get the last SSL error
  165. sslerr = X509_STORE_CTX_get_error(store);
  166. switch (sslerr)
  167. {
  168. case X509_V_ERR_CERT_HAS_EXPIRED:
  169. case X509_V_ERR_CERT_NOT_YET_VALID:
  170. case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
  171. case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
  172. // always ignore these errors
  173. X509_STORE_CTX_set_error(store, X509_V_OK);
  174. ok = 1;
  175. break;
  176. default:
  177. break;
  178. }
  179. }
  180. return ok;
  181. }