http_impl.c 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419
  1. /* --- BEGIN COPYRIGHT BLOCK ---
  2. * This Program is free software; you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation; version 2 of the License.
  5. *
  6. * This Program is distributed in the hope that it will be useful, but WITHOUT
  7. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  8. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  9. *
  10. * You should have received a copy of the GNU General Public License along with
  11. * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
  12. * Place, Suite 330, Boston, MA 02111-1307 USA.
  13. *
  14. * In addition, as a special exception, Red Hat, Inc. gives You the additional
  15. * right to link the code of this Program with code not covered under the GNU
  16. * General Public License ("Non-GPL Code") and to distribute linked combinations
  17. * including the two, subject to the limitations in this paragraph. Non-GPL Code
  18. * permitted under this exception must only link to the code of this Program
  19. * through those well defined interfaces identified in the file named EXCEPTION
  20. * found in the source code files (the "Approved Interfaces"). The files of
  21. * Non-GPL Code may instantiate templates or use macros or inline functions from
  22. * the Approved Interfaces without causing the resulting work to be covered by
  23. * the GNU General Public License. Only Red Hat, Inc. may make changes or
  24. * additions to the list of Approved Interfaces. You must obey the GNU General
  25. * Public License in all respects for all of the Program code and other code used
  26. * in conjunction with the Program except the Non-GPL Code covered by this
  27. * exception. If you modify this file, you may extend this exception to your
  28. * version of the file, but you are not obligated to do so. If you do not wish to
  29. * provide this exception without modification, you must delete this exception
  30. * statement from your version and license this file solely under the GPL without
  31. * exception.
  32. *
  33. *
  34. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  35. * Copyright (C) 2005 Red Hat, Inc.
  36. * All rights reserved.
  37. * --- END COPYRIGHT BLOCK --- */
  38. #ifdef HAVE_CONFIG_H
  39. # include <config.h>
  40. #endif
  41. /**
  42. * Implementation of a Simple HTTP Client
  43. */
  44. #include <stdio.h>
  45. #include <string.h>
  46. #include "nspr.h"
  47. #include "nss.h"
  48. #include "pk11func.h"
  49. #include "ssl.h"
  50. #include "prprf.h"
  51. #include "plstr.h"
  52. #include "slapi-plugin.h"
  53. #include "http_client.h"
  54. #include "secerr.h"
  55. #include "sslerr.h"
  56. #include "slap.h"
  57. #include "slapi-private.h"
  58. #include "slapi-plugin-compat4.h"
  59. /* get file mode flags for unix */
  60. #ifndef _WIN32
  61. #include <sys/stat.h>
  62. #endif
  63. /*** from proto-slap.h ***/
  64. int slapd_log_error_proc( char *subsystem, char *fmt, ... );
  65. char *config_get_instancedir();
  66. /*** from ldaplog.h ***/
  67. /* edited ldaplog.h for LDAPDebug()*/
  68. #ifndef _LDAPLOG_H
  69. #define _LDAPLOG_H
  70. #ifdef __cplusplus
  71. extern "C" {
  72. #endif
  73. #ifdef BUILD_STANDALONE
  74. #define slapi_log_error(a,b,c,d) printf((c),(d))
  75. #define stricmp strcasecmp
  76. #endif
  77. #define LDAP_DEBUG_TRACE 0x00001 /* 1 */
  78. #define LDAP_DEBUG_ANY 0x04000 /* 16384 */
  79. #define LDAP_DEBUG_PLUGIN 0x10000 /* 65536 */
  80. /* debugging stuff */
  81. # ifdef _WIN32
  82. extern int *module_ldap_debug;
  83. # define LDAPDebug( level, fmt, arg1, arg2, arg3 ) \
  84. { \
  85. if ( *module_ldap_debug & level ) { \
  86. slapd_log_error_proc( NULL, fmt, arg1, arg2, arg3 ); \
  87. } \
  88. }
  89. # else /* _WIN32 */
  90. extern int slapd_ldap_debug;
  91. # define LDAPDebug( level, fmt, arg1, arg2, arg3 ) \
  92. { \
  93. if ( slapd_ldap_debug & level ) { \
  94. slapd_log_error_proc( NULL, fmt, arg1, arg2, arg3 ); \
  95. } \
  96. }
  97. # endif /* Win32 */
  98. #ifdef __cplusplus
  99. }
  100. #endif
  101. #endif /* _LDAP_H */
  102. #define HTTP_PLUGIN_SUBSYSTEM "http-client-plugin" /* used for logging */
  103. #define HTTP_IMPL_SUCCESS 0
  104. #define HTTP_IMPL_FAILURE -1
  105. #define HTTP_REQ_TYPE_GET 1
  106. #define HTTP_REQ_TYPE_REDIRECT 2
  107. #define HTTP_REQ_TYPE_POST 3
  108. #define HTTP_GET "GET"
  109. #define HTTP_POST "POST"
  110. #define HTTP_PROTOCOL "HTTP/1.0"
  111. #define HTTP_CONTENT_LENGTH "Content-length:"
  112. #define HTTP_CONTENT_TYPE_URL_ENCODED "Content-type: application/x-www-form-urlencoded"
  113. #define HTTP_GET_STD_LEN 18
  114. #define HTTP_POST_STD_LEN 85
  115. #define HTTP_DEFAULT_BUFFER_SIZE 4096
  116. #define HTTP_RESPONSE_REDIRECT (retcode == 302 || retcode == 301)
  117. /**
  118. * Error strings used for logging error messages
  119. */
  120. #define HTTP_ERROR_BAD_URL " Badly formatted URL"
  121. #define HTTP_ERROR_NET_ADDR " NetAddr initialization failed"
  122. #define HTTP_ERROR_SOCKET_CREATE " Creation of socket failed"
  123. #define HTTP_ERROR_SSLSOCKET_CREATE " Creation of SSL socket failed"
  124. #define HTTP_ERROR_CONNECT_FAILED " Couldn't connect to remote host"
  125. #define HTTP_ERROR_SEND_REQ " Send request failed"
  126. #define HTTP_ERROR_BAD_RESPONSE " Invalid response from remote host"
  127. #define HTTP_PLUGIN_DN "cn=HTTP Client,cn=plugins,cn=config"
  128. #define CONFIG_DN "cn=config"
  129. #define ATTR_CONNECTION_TIME_OUT "nsHTTPConnectionTimeOut"
  130. #define ATTR_READ_TIME_OUT "nsHTTPReadTimeOut"
  131. #define ATTR_RETRY_COUNT "nsHTTPRetryCount"
  132. #define ATTR_DS_SECURITY "nsslapd-security"
  133. #define ATTR_INSTANCE_PATH "nsslapd-errorlog"
  134. /*static Slapi_ComponentId *plugin_id = NULL;*/
  135. typedef struct {
  136. int retryCount;
  137. int connectionTimeOut;
  138. int readTimeOut;
  139. int nssInitialized;
  140. char *DS_sslOn;
  141. } httpPluginConfig;
  142. httpPluginConfig *httpConfig;
  143. /**
  144. * Public functions
  145. */
  146. int http_impl_init(Slapi_ComponentId *plugin_id);
  147. int http_impl_get_text(char *url, char **data, int *bytesRead);
  148. int http_impl_get_binary(char *url, char **data, int *bytesRead);
  149. int http_impl_get_redirected_uri(char *url, char **data, int *bytesRead);
  150. int http_impl_post(char *url, httpheader **httpheaderArray, char *body, char **data, int *bytesRead);
  151. void http_impl_shutdown();
  152. /**
  153. * Http handling functions
  154. */
  155. static int doRequest(const char *url, httpheader **httpheaderArray, char *body, char **buf, int *bytesRead, int reqType);
  156. static int doRequestRetry(const char *url, httpheader **httpheaderArray, char *body, char **buf, int *bytesRead, int reqType);
  157. static void setTCPNoDelay(PRFileDesc* fd);
  158. static PRStatus sendGetReq(PRFileDesc *fd, const char *path);
  159. static PRStatus sendPostReq(PRFileDesc *fd, const char *path, httpheader **httpheaderArray, char *body);
  160. static PRStatus processResponse(PRFileDesc *fd, char **resBUF, int *bytesRead, int reqType);
  161. static PRStatus getChar(PRFileDesc *fd, char *buf);
  162. static PRInt32 http_read(PRFileDesc *fd, char *buf, int size);
  163. static PRStatus getBody(PRFileDesc *fd, char **buf, int *actualBytesRead);
  164. static PRBool isWhiteSpace(char ch);
  165. static PRStatus sendFullData( PRFileDesc *fd, char *buf, int timeOut);
  166. /**
  167. * Helper functions to parse URL
  168. */
  169. static PRStatus parseURI(const char *url, char **host, PRInt32 *port, char **path, int *sslOn);
  170. static void toLowerCase(char* str);
  171. static PRStatus parseAtPort(const char* url, PRInt32 *port, char **path);
  172. static PRStatus parseAtPath(const char *url, char **path);
  173. static PRInt32 getPort(const char* src);
  174. static PRBool isAsciiSpace(char aChar);
  175. static PRBool isAsciiDigit(char aChar);
  176. static char * isHttpReq(const char *url, int *sslOn);
  177. /*To get config from entry*/
  178. static int readConfigLDAPurl(Slapi_ComponentId *plugin_id, char *plugindn);
  179. static int parseHTTPConfigEntry(Slapi_Entry *e);
  180. static int parseConfigEntry(Slapi_Entry *e);
  181. /*SSL functions */
  182. PRFileDesc* setupSSLSocket(PRFileDesc* fd);
  183. /*SSL callback functions */
  184. SECStatus badCertHandler(void *arg, PRFileDesc *socket);
  185. SECStatus authCertificate(void *arg, PRFileDesc *socket, PRBool checksig, PRBool isServer);
  186. SECStatus getClientAuthData(void *arg, PRFileDesc *socket,struct CERTDistNamesStr *caNames, struct CERTCertificateStr **pRetCert, struct SECKEYPrivateKeyStr **pRetKey);
  187. SECStatus handshakeCallback(PRFileDesc *socket, void *arg);
  188. static int doRequestRetry(const char *url, httpheader **httpheaderArray, char *body, char **buf, int *bytesRead, int reqType)
  189. {
  190. int status = HTTP_IMPL_SUCCESS;
  191. int retrycnt = 0;
  192. int i = 1;
  193. retrycnt = httpConfig->retryCount;
  194. if (retrycnt == 0) {
  195. LDAPDebug( LDAP_DEBUG_PLUGIN, "doRequestRetry: Retry Count cannot be read. Setting to default value of 3 \n", 0,0,0);
  196. retrycnt = 3;
  197. }
  198. status = doRequest(url, httpheaderArray, body, buf, bytesRead, reqType);
  199. if (status != HTTP_IMPL_SUCCESS) {
  200. LDAPDebug( LDAP_DEBUG_PLUGIN, "doRequestRetry: Failed to perform http request \n", 0,0,0);
  201. while (retrycnt > 0) {
  202. LDAPDebug( LDAP_DEBUG_PLUGIN, "doRequestRetry: Retrying http request %d.\n", i,0,0);
  203. status = doRequest(url, httpheaderArray, body, buf, bytesRead, reqType);
  204. if (status == HTTP_IMPL_SUCCESS) {
  205. break;
  206. }
  207. retrycnt--;
  208. i++;
  209. }
  210. if (status != HTTP_IMPL_SUCCESS) {
  211. LDAPDebug( LDAP_DEBUG_ANY, "doRequestRetry: Failed to perform http request after %d attempts.\n", i,0,0);
  212. LDAPDebug( LDAP_DEBUG_ANY, "doRequestRetry: Verify plugin URI configuration and contact Directory Administrator.\n",0,0,0);
  213. }
  214. }
  215. return status;
  216. }
  217. static int doRequest(const char *url, httpheader **httpheaderArray, char *body, char **buf, int *bytesRead, int reqType)
  218. {
  219. PRStatus status = PR_SUCCESS;
  220. char *host = NULL;
  221. char *path = NULL;
  222. PRFileDesc *fd = NULL;
  223. PRNetAddr addr;
  224. PRInt32 port;
  225. PRInt32 errcode = 0;
  226. PRInt32 http_connection_time_out = 0;
  227. PRInt32 sslOn;
  228. LDAPDebug( LDAP_DEBUG_PLUGIN, "--> doRequest -- BEGIN\n",0,0,0);
  229. LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> url=[%s] \n",url,0,0);
  230. /* Parse the URL and initialize the host, port, path */
  231. if (parseURI(url, &host, &port, &path, &sslOn) == PR_FAILURE) {
  232. slapi_log_error( SLAPI_LOG_FATAL, HTTP_PLUGIN_SUBSYSTEM,
  233. "doRequest: %s \n", HTTP_ERROR_BAD_URL);
  234. status = PR_FAILURE;
  235. goto bail;
  236. }
  237. LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> host=[%s] port[%d] path[%s] \n",host,port,path);
  238. /* Initialize the Net Addr */
  239. if (PR_StringToNetAddr(host, &addr) == PR_FAILURE) {
  240. char buf[PR_NETDB_BUF_SIZE];
  241. PRHostEnt ent;
  242. status = PR_GetIPNodeByName(host, PR_AF_INET, PR_AI_DEFAULT, buf, sizeof(buf), &ent);
  243. if (status == PR_SUCCESS) {
  244. PR_EnumerateHostEnt(0, &ent, (PRUint16)port, &addr);
  245. } else {
  246. slapi_log_error( SLAPI_LOG_FATAL, HTTP_PLUGIN_SUBSYSTEM,
  247. "doRequest: %s\n", HTTP_ERROR_NET_ADDR);
  248. status = HTTP_CLIENT_ERROR_NET_ADDR;
  249. goto bail;
  250. }
  251. } else {
  252. addr.inet.port = (PRUint16)port;
  253. }
  254. LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> Successfully created NetAddr \n",0,0,0);
  255. /* open a TCP connection to the server */
  256. fd = PR_NewTCPSocket();
  257. if (!fd) {
  258. slapi_log_error( SLAPI_LOG_FATAL, HTTP_PLUGIN_SUBSYSTEM,
  259. "doRequest: %s\n", HTTP_ERROR_SOCKET_CREATE);
  260. status = HTTP_CLIENT_ERROR_SOCKET_CREATE;
  261. goto bail;
  262. }
  263. LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> Successfully created New TCP Socket \n",0,0,0);
  264. /* immediately send the response */
  265. setTCPNoDelay(fd);
  266. if (sslOn) {
  267. fd = setupSSLSocket(fd);
  268. if (fd == NULL) {
  269. slapi_log_error( SLAPI_LOG_FATAL, HTTP_PLUGIN_SUBSYSTEM,
  270. "doRequest: %s\n", HTTP_ERROR_SSLSOCKET_CREATE);
  271. status = HTTP_CLIENT_ERROR_SSLSOCKET_CREATE;
  272. goto bail;
  273. }
  274. if (SSL_SetURL(fd, host) != 0) {
  275. errcode = PR_GetError();
  276. slapi_log_error( SLAPI_LOG_FATAL, HTTP_PLUGIN_SUBSYSTEM,
  277. "doRequest: SSL_SetURL -> NSPR Error code (%d) \n", errcode);
  278. status = HTTP_CLIENT_ERROR_SSLSOCKET_CREATE;
  279. goto bail;
  280. }
  281. }
  282. http_connection_time_out = httpConfig->connectionTimeOut;
  283. /* connect to the host */
  284. if (PR_Connect(fd, &addr, PR_MillisecondsToInterval(http_connection_time_out)) == PR_FAILURE) {
  285. errcode = PR_GetError();
  286. slapi_log_error( SLAPI_LOG_FATAL, HTTP_PLUGIN_SUBSYSTEM,
  287. "doRequest: %s (%s:%d) -> NSPR Error code (%d)\n",
  288. HTTP_ERROR_CONNECT_FAILED, host, addr.inet.port, errcode);
  289. status = HTTP_CLIENT_ERROR_CONNECT_FAILED;
  290. goto bail;
  291. }
  292. LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> Successfully connected to host [%s] \n",host,0,0);
  293. /* send the request to the server */
  294. if (reqType == HTTP_REQ_TYPE_POST) {
  295. if (sendPostReq(fd, path, httpheaderArray, body) == PR_FAILURE) {
  296. slapi_log_error( SLAPI_LOG_FATAL, HTTP_PLUGIN_SUBSYSTEM,
  297. "doRequest-sendPostReq: %s (%s)\n", HTTP_ERROR_SEND_REQ, path);
  298. status = HTTP_CLIENT_ERROR_SEND_REQ;
  299. goto bail;
  300. }
  301. }
  302. else {
  303. if (sendGetReq(fd, path) == PR_FAILURE) {
  304. slapi_log_error( SLAPI_LOG_FATAL, HTTP_PLUGIN_SUBSYSTEM,
  305. "doRequest-sendGetReq: %s (%s)\n", HTTP_ERROR_SEND_REQ, path);
  306. status = HTTP_CLIENT_ERROR_SEND_REQ;
  307. goto bail;
  308. }
  309. }
  310. LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> Successfully sent the request [%s] \n",path,0,0);
  311. /* read the response */
  312. if (processResponse(fd, buf, bytesRead, reqType) == PR_FAILURE) {
  313. slapi_log_error( SLAPI_LOG_FATAL, HTTP_PLUGIN_SUBSYSTEM,
  314. "doRequest: %s (%s)\n", HTTP_ERROR_BAD_RESPONSE, url);
  315. status = HTTP_CLIENT_ERROR_BAD_RESPONSE;
  316. goto bail;
  317. }
  318. LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> Successfully read the response\n",0,0,0);
  319. bail:
  320. if (host) {
  321. PR_Free(host);
  322. }
  323. if (path) {
  324. PR_Free(path);
  325. }
  326. if (fd) {
  327. PR_Close(fd);
  328. fd = NULL;
  329. }
  330. LDAPDebug( LDAP_DEBUG_PLUGIN, "<-- doRequest -- END\n",0,0,0);
  331. return status;
  332. }
  333. static PRStatus processResponse(PRFileDesc *fd, char **resBUF, int *bytesRead, int reqType)
  334. {
  335. PRStatus status = PR_SUCCESS;
  336. char *location = NULL;
  337. char *protocol = NULL;
  338. char *statusNum = NULL;
  339. char *statusString = NULL;
  340. char *headers = NULL;
  341. char tmp[HTTP_DEFAULT_BUFFER_SIZE];
  342. int pos=0;
  343. char ch;
  344. int index;
  345. int retcode;
  346. PRBool doneParsing = PR_FALSE;
  347. PRBool isRedirect = PR_FALSE;
  348. char name[HTTP_DEFAULT_BUFFER_SIZE];
  349. char value[HTTP_DEFAULT_BUFFER_SIZE];
  350. PRBool atEOL = PR_FALSE;
  351. PRBool inName = PR_TRUE;
  352. /* PKBxxx: If we are getting a redirect and the response is more the
  353. * the HTTP_DEFAULT_BUFFER_SIZE, it will cause the server to crash. A 4k
  354. * buffer should be good enough.
  355. */
  356. LDAPDebug( LDAP_DEBUG_PLUGIN, "--> processResponse -- BEGIN\n",0,0,0);
  357. headers = (char *)PR_Calloc(1, 4 * HTTP_DEFAULT_BUFFER_SIZE);
  358. /* Get protocol string */
  359. index = 0;
  360. while (1) {
  361. status = getChar(fd, headers+pos);
  362. if (status == PR_FAILURE) {
  363. /* Error : */
  364. goto bail;
  365. }
  366. ch = (char)headers[pos];
  367. pos++;
  368. if (!isWhiteSpace(ch)) {
  369. tmp[index++] = ch;
  370. } else {
  371. break;
  372. }
  373. }
  374. tmp[index] = '\0';
  375. protocol = PL_strdup(tmp);
  376. LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> protocol=[%s] \n",protocol,0,0);
  377. /* Get status num */
  378. index = 0;
  379. while (1) {
  380. status = getChar(fd, headers+pos);
  381. if (status == PR_FAILURE) {
  382. /* Error : */
  383. goto bail;
  384. }
  385. ch = (char)headers[pos];
  386. pos++;
  387. if (!isWhiteSpace(ch)) {
  388. tmp[index++] = ch;
  389. } else {
  390. break;
  391. }
  392. }
  393. tmp[index] = '\0';
  394. statusNum = PL_strdup(tmp);
  395. retcode=atoi(tmp);
  396. LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> statusNum=[%s] \n",statusNum,0,0);
  397. if (HTTP_RESPONSE_REDIRECT && (reqType == HTTP_REQ_TYPE_REDIRECT)) {
  398. isRedirect = PR_TRUE;
  399. }
  400. /* Get status string */
  401. if (ch != '\r')
  402. {
  403. index = 0;
  404. while (ch != '\r') {
  405. status = getChar(fd, headers+pos);
  406. if (status == PR_FAILURE) {
  407. /* Error : */
  408. goto bail;
  409. }
  410. ch = (char)headers[pos];
  411. pos++;
  412. tmp[index++] = ch;
  413. }
  414. tmp[index] = '\0';
  415. statusString = PL_strdup(tmp);
  416. LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> statusString [%s] \n",statusString,0,0);
  417. }
  418. /**
  419. * Skip CRLF
  420. */
  421. status = getChar(fd, headers+pos);
  422. if (status == PR_FAILURE) {
  423. /* Error : */
  424. goto bail;
  425. }
  426. ch = (char)headers[pos];
  427. pos++;
  428. /**
  429. * loop over response headers
  430. */
  431. index = 0;
  432. while (!doneParsing) {
  433. status = getChar(fd, headers+pos);
  434. if (status == PR_FAILURE) {
  435. /* Error : */
  436. goto bail;
  437. }
  438. ch = (char)headers[pos];
  439. pos++;
  440. switch(ch)
  441. {
  442. case ':':
  443. if (inName) {
  444. name[index] = '\0';
  445. index = 0;
  446. inName = PR_FALSE;
  447. /* skip whitespace */
  448. ch = ' ';
  449. /* status = getChar(fd, headers+pos);
  450. if (status == PR_FAILURE) {
  451. goto bail;
  452. }
  453. ch = (char)headers[pos];
  454. pos++; */
  455. while(isWhiteSpace(ch)) {
  456. status = getChar(fd, headers+pos);
  457. if (status == PR_FAILURE) {
  458. /* Error : */
  459. goto bail;
  460. }
  461. ch = (char)headers[pos];
  462. pos++;
  463. }
  464. value[index++] = ch;
  465. } else {
  466. value[index++] = ch;
  467. }
  468. break;
  469. case '\r':
  470. if (inName && !atEOL) {
  471. return PR_FALSE;
  472. }
  473. break;
  474. case '\n':
  475. if (atEOL) {
  476. doneParsing = PR_TRUE;
  477. break;
  478. }
  479. if (inName) {
  480. return PR_FALSE;
  481. }
  482. value[index] = '\0';
  483. index = 0;
  484. inName = PR_TRUE;
  485. LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> name=[%s] value=[%s]\n",name,value,0);
  486. if (isRedirect && !PL_strcasecmp(name,"location")) {
  487. location = PL_strdup(value);
  488. }
  489. atEOL = PR_TRUE;
  490. break;
  491. default:
  492. atEOL = PR_FALSE;
  493. if (inName) {
  494. name[index++] = ch;
  495. } else {
  496. value[index++] = ch;
  497. }
  498. break;
  499. }
  500. }
  501. if (!isRedirect) {
  502. getBody(fd, resBUF, bytesRead);
  503. } else {
  504. *resBUF = PL_strdup(location);
  505. *bytesRead = strlen(location);
  506. }
  507. LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> Response Buffer=[%s] bytesRead=[%d] \n",*resBUF,*bytesRead,0);
  508. bail:
  509. if (headers) {
  510. PR_Free(headers);
  511. }
  512. if (protocol) {
  513. PL_strfree(protocol);
  514. }
  515. if (statusNum) {
  516. PL_strfree(statusNum);
  517. }
  518. if (statusString) {
  519. PL_strfree(statusString);
  520. }
  521. if (location) {
  522. PL_strfree(location);
  523. }
  524. LDAPDebug( LDAP_DEBUG_PLUGIN, "<-- processResponse -- END\n",0,0,0);
  525. return status;
  526. }
  527. static PRStatus sendGetReq(PRFileDesc *fd, const char *path)
  528. {
  529. PRStatus status = PR_SUCCESS;
  530. char *reqBUF = NULL;
  531. PRInt32 http_connection_time_out = 0;
  532. int buflen = (HTTP_GET_STD_LEN + strlen(path));
  533. reqBUF = (char *)PR_Calloc(1, buflen);
  534. strcpy(reqBUF, HTTP_GET);
  535. strcat(reqBUF, " ");
  536. strcat(reqBUF, path);
  537. strcat(reqBUF, " ");
  538. strcat(reqBUF, HTTP_PROTOCOL);
  539. strcat(reqBUF, "\r\n\r\n\0");
  540. http_connection_time_out = httpConfig->connectionTimeOut;
  541. status = sendFullData( fd, reqBUF, http_connection_time_out);
  542. if (reqBUF) {
  543. PR_Free(reqBUF);
  544. reqBUF = 0;
  545. }
  546. return status;
  547. }
  548. static PRStatus sendFullData( PRFileDesc *fd, char *buf, int timeOut)
  549. {
  550. int dataSent = 0;
  551. int bufLen = strlen(buf);
  552. int retVal = 0;
  553. PRInt32 errcode = 0;
  554. while (dataSent < bufLen)
  555. {
  556. retVal = PR_Send(fd, buf+dataSent, bufLen-dataSent, 0, PR_MillisecondsToInterval(timeOut));
  557. if (retVal == -1 )
  558. break;
  559. dataSent += retVal;
  560. }
  561. if (dataSent == bufLen )
  562. return PR_SUCCESS;
  563. else
  564. {
  565. errcode = PR_GetError();
  566. slapi_log_error( SLAPI_LOG_FATAL, HTTP_PLUGIN_SUBSYSTEM,
  567. "sendFullData: dataSent=%d bufLen=%d -> NSPR Error code (%d)\n",
  568. dataSent, bufLen, errcode);
  569. LDAPDebug( LDAP_DEBUG_PLUGIN, "---------->NSPR Error code (%d) \n", errcode,0,0);
  570. return PR_FAILURE;
  571. }
  572. }
  573. static PRStatus sendPostReq(PRFileDesc *fd, const char *path, httpheader **httpheaderArray, char *body)
  574. {
  575. PRStatus status = PR_SUCCESS;
  576. char body_len_str[20];
  577. char *reqBUF = NULL;
  578. PRInt32 http_connection_time_out = 0;
  579. int i = 0;
  580. int body_len, buflen = 0;
  581. if (body) {
  582. body_len = strlen(body);
  583. } else {
  584. body_len = 0;
  585. }
  586. PR_snprintf(body_len_str, sizeof(body_len_str), "%d", body_len);
  587. buflen = (HTTP_POST_STD_LEN + strlen(path) + body_len + strlen(body_len_str));
  588. for (i = 0; httpheaderArray[i] != NULL; i++) {
  589. if (httpheaderArray[i]->name != NULL)
  590. {
  591. buflen += strlen(httpheaderArray[i]->name) + 2;
  592. if (httpheaderArray[i]->value != NULL)
  593. buflen += strlen(httpheaderArray[i]->value) + 2;
  594. }
  595. }
  596. reqBUF = (char *)PR_Calloc(1, buflen);
  597. strcpy(reqBUF, HTTP_POST);
  598. strcat(reqBUF, " ");
  599. strcat(reqBUF, path);
  600. strcat(reqBUF, " ");
  601. strcat(reqBUF, HTTP_PROTOCOL);
  602. strcat(reqBUF, "\r\n");
  603. strcat(reqBUF, HTTP_CONTENT_LENGTH);
  604. strcat(reqBUF, " ");
  605. strcat(reqBUF, body_len_str);
  606. strcat(reqBUF, "\r\n");
  607. strcat(reqBUF, HTTP_CONTENT_TYPE_URL_ENCODED);
  608. strcat(reqBUF, "\r\n");
  609. for (i = 0; httpheaderArray[i] != NULL; i++) {
  610. if (httpheaderArray[i]->name != NULL)
  611. strcat(reqBUF, httpheaderArray[i]->name);
  612. strcat(reqBUF, ": ");
  613. if (httpheaderArray[i]->value != NULL)
  614. strcat(reqBUF, httpheaderArray[i]->value);
  615. strcat(reqBUF, "\r\n");
  616. }
  617. strcat(reqBUF, "\r\n");
  618. if (body) {
  619. strcat(reqBUF, body);
  620. }
  621. strcat(reqBUF, "\0");
  622. LDAPDebug( LDAP_DEBUG_PLUGIN, "---------->reqBUF is %s \n",reqBUF,0,0);
  623. http_connection_time_out = httpConfig->connectionTimeOut;
  624. status = sendFullData( fd, reqBUF, http_connection_time_out);
  625. if (reqBUF) {
  626. PR_Free(reqBUF);
  627. reqBUF = 0;
  628. }
  629. return status;
  630. }
  631. static PRStatus getChar(PRFileDesc *fd, char *buf)
  632. {
  633. PRInt32 bytesRead = http_read(fd, buf, 1);
  634. if (bytesRead <=0) {
  635. PRInt32 errcode = PR_GetError();
  636. slapi_log_error( SLAPI_LOG_FATAL, HTTP_PLUGIN_SUBSYSTEM,
  637. "getChar: NSPR Error code (%d)\n", errcode);
  638. return PR_FAILURE;
  639. }
  640. return PR_SUCCESS;
  641. }
  642. static PRStatus getBody(PRFileDesc *fd, char **buf, int *actualBytesRead)
  643. {
  644. int totalBytesRead = 0;
  645. int size = 4 * HTTP_DEFAULT_BUFFER_SIZE;
  646. int bytesRead = size;
  647. char *data = (char *) PR_Calloc(1, size);
  648. while (bytesRead == size) {
  649. bytesRead = http_read(fd, (data+totalBytesRead), size);
  650. if (bytesRead <= 0) {
  651. /* Read error */
  652. return PR_FAILURE;
  653. }
  654. if (bytesRead == size) {
  655. /* more data to be read so increase the buffer */
  656. size = size * 2 ;
  657. data = (char *) PR_Realloc(data, size);
  658. }
  659. totalBytesRead += bytesRead;
  660. }
  661. *buf = data;
  662. *actualBytesRead = totalBytesRead;
  663. return PR_SUCCESS;
  664. }
  665. static PRInt32 http_read(PRFileDesc *fd, char *buf, int size)
  666. {
  667. PRInt32 http_read_time_out = 0;
  668. http_read_time_out = httpConfig->readTimeOut;
  669. return PR_Recv(fd, buf, size, 0, PR_MillisecondsToInterval(http_read_time_out));
  670. }
  671. static PRBool isWhiteSpace(char ch)
  672. {
  673. PRBool b = PR_FALSE;
  674. if (ch == ' ') {
  675. b = PR_TRUE;
  676. }
  677. return b;
  678. }
  679. static PRStatus parseURI(const char *urlstr, char **host, PRInt32 *port, char **path, int *sslOn)
  680. {
  681. PRStatus status = PR_SUCCESS;
  682. char *brk;
  683. int len;
  684. static const char delimiters[] = ":/?#";
  685. char *url = isHttpReq(urlstr, sslOn);
  686. if (*sslOn) {
  687. *port = 443;
  688. }
  689. else {
  690. *port = 80;
  691. }
  692. if (url == NULL) {
  693. /* Error : */
  694. status = PR_FAILURE;
  695. goto bail;
  696. }
  697. len = PL_strlen(url);
  698. /* Currently we do not support Ipv6 addresses */
  699. brk = PL_strpbrk(url, delimiters);
  700. if (!brk) {
  701. *host = PL_strndup(url, len);
  702. toLowerCase(*host);
  703. goto bail;
  704. }
  705. switch (*brk)
  706. {
  707. case '/' :
  708. case '?' :
  709. case '#' :
  710. /* Get the Host, the rest is Path */
  711. *host = PL_strndup(url, (brk - url));
  712. toLowerCase(*host);
  713. status = parseAtPath(brk, path);
  714. break;
  715. case ':' :
  716. /* Get the Host and process port, path */
  717. *host = PL_strndup(url, (brk - url));
  718. toLowerCase(*host);
  719. status = parseAtPort(brk+1, port, path);
  720. break;
  721. default:
  722. /* Error : HTTP_BAD_URL */
  723. break;
  724. }
  725. bail:
  726. if (url) {
  727. PR_Free(url);
  728. }
  729. return status;
  730. }
  731. static PRStatus parseAtPort(const char* url, PRInt32 *port, char **path)
  732. {
  733. PRStatus status = PR_SUCCESS;
  734. static const char delimiters[] = "/?#";
  735. char* brk = PL_strpbrk(url, delimiters);
  736. if (!brk) /* everything is a Port */
  737. {
  738. *port = getPort(url);
  739. if (*port <= 0) {
  740. /* Error : HTTP_BAD_URL */
  741. return PR_FAILURE;
  742. } else {
  743. return status;
  744. }
  745. }
  746. switch (*brk)
  747. {
  748. case '/' :
  749. case '?' :
  750. case '#' :
  751. /* Get the Port, the rest is Path */
  752. *port = getPort(url);
  753. if (*port <= 0) {
  754. /* Error : HTTP_BAD_URL */
  755. return PR_FAILURE;
  756. }
  757. status = parseAtPath(brk, path);
  758. break;
  759. default:
  760. /* Error : HTTP_BAD_URL */
  761. break;
  762. }
  763. return status;
  764. }
  765. static PRStatus parseAtPath(const char *url, char **path)
  766. {
  767. PRStatus status = PR_SUCCESS;
  768. char *dir = "%s%s";
  769. *path = (char *)PR_Calloc(1, strlen(dir) + strlen(url) + 2);
  770. /* Just write the path and check for a starting / */
  771. if ('/' != *url) {
  772. sprintf(*path, dir, "/", url);
  773. } else {
  774. strcpy(*path, url);
  775. }
  776. if (!*path) {
  777. /* Error : HTTP_BAD_URL */
  778. status = PR_FAILURE;
  779. }
  780. return status;
  781. }
  782. static void toLowerCase(char* str)
  783. {
  784. if (str) {
  785. char* lstr = str;
  786. PRInt8 shift = 'a' - 'A';
  787. for(; (*lstr != '\0'); ++lstr) {
  788. if ((*(lstr) <= 'Z') && (*(lstr) >= 'A')) {
  789. *(lstr) = *(lstr) + shift;
  790. }
  791. }
  792. }
  793. }
  794. static PRInt32 getPort(const char* src)
  795. {
  796. /* search for digits up to a slash or the string ends */
  797. const char* port = src;
  798. PRInt32 returnValue = -1;
  799. char c;
  800. /* skip leading white space */
  801. while (isAsciiSpace(*port))
  802. port++;
  803. while ((c = *port++) != '\0') {
  804. /* stop if slash or ? or # reached */
  805. if (c == '/' || c == '?' || c == '#')
  806. break;
  807. else if (!isAsciiDigit(c))
  808. return returnValue;
  809. }
  810. return (0 < PR_sscanf(src, "%d", &returnValue)) ? returnValue : -1;
  811. }
  812. static PRBool isAsciiSpace(char aChar)
  813. {
  814. if ((aChar == ' ') || (aChar == '\r') || (aChar == '\n') || (aChar == '\t')) {
  815. return PR_TRUE;
  816. }
  817. return PR_FALSE;
  818. }
  819. static PRBool isAsciiDigit(char aChar)
  820. {
  821. if ((aChar >= '0') && (aChar <= '9')) {
  822. return PR_TRUE;
  823. }
  824. return PR_FALSE;
  825. }
  826. static void setTCPNoDelay(PRFileDesc* fd)
  827. {
  828. PRStatus status = PR_SUCCESS;
  829. PRSocketOptionData opt;
  830. opt.option = PR_SockOpt_NoDelay;
  831. opt.value.no_delay = PR_FALSE;
  832. status = PR_GetSocketOption(fd, &opt);
  833. if (status == PR_FAILURE) {
  834. return;
  835. }
  836. opt.option = PR_SockOpt_NoDelay;
  837. opt.value.no_delay = PR_TRUE;
  838. status = PR_SetSocketOption(fd, &opt);
  839. if (status == PR_FAILURE) {
  840. return;
  841. }
  842. return;
  843. }
  844. static char * isHttpReq(const char *url, int *sslOn)
  845. {
  846. static const char http_protopol_header[] = "http://";
  847. static const char https_protopol_header[] = "https://";
  848. char *newstr = NULL;
  849. /* skip leading white space */
  850. while (isAsciiSpace(*url))
  851. url++;
  852. if (strncmp(url, http_protopol_header, strlen(http_protopol_header)) == 0) {
  853. newstr = (char *)PR_Calloc(1, (strlen(url)-strlen(http_protopol_header) + 1));
  854. strcpy(newstr, url+7);
  855. strcat(newstr,"\0");
  856. *sslOn = 0;
  857. }
  858. else if (strncmp(url, https_protopol_header, strlen(https_protopol_header)) == 0) {
  859. newstr = (char *)PR_Calloc(1, (strlen(url)-strlen(https_protopol_header) + 1));
  860. strcpy(newstr, url+8);
  861. strcat(newstr,"\0");
  862. *sslOn = 1;
  863. }
  864. return newstr;
  865. }
  866. PRFileDesc* setupSSLSocket(PRFileDesc* fd)
  867. {
  868. SECStatus secStatus;
  869. PRFileDesc* sslSocket;
  870. PRSocketOptionData socketOption;
  871. char *certNickname = NULL;
  872. socketOption.option = PR_SockOpt_Nonblocking;
  873. socketOption.value.non_blocking = PR_FALSE;
  874. if( PR_SetSocketOption(fd, &socketOption) != 0) {
  875. slapi_log_error( SLAPI_LOG_PLUGIN, HTTP_PLUGIN_SUBSYSTEM,
  876. "Cannot set socket option NSS \n");
  877. return NULL;
  878. }
  879. sslSocket = SSL_ImportFD(NULL, fd);
  880. if (!sslSocket) {
  881. slapi_log_error( SLAPI_LOG_PLUGIN, HTTP_PLUGIN_SUBSYSTEM,
  882. "setupSSLSocket: Cannot import to SSL Socket\n" );
  883. goto sslbail;
  884. }
  885. slapi_log_error( SLAPI_LOG_FATAL, HTTP_PLUGIN_SUBSYSTEM,
  886. "setupSSLSocket: setupssl socket created\n" );
  887. secStatus = SSL_OptionSet(sslSocket, SSL_SECURITY, 1);
  888. if (SECSuccess != secStatus) {
  889. slapi_log_error( SLAPI_LOG_PLUGIN, HTTP_PLUGIN_SUBSYSTEM,
  890. "setupSSLSocket: Cannot set SSL_SECURITY option\n");
  891. goto sslbail;
  892. }
  893. secStatus = SSL_OptionSet(sslSocket, SSL_HANDSHAKE_AS_CLIENT, 1);
  894. if (SECSuccess != secStatus) {
  895. slapi_log_error( SLAPI_LOG_PLUGIN, HTTP_PLUGIN_SUBSYSTEM,
  896. "setupSSLSocket: CAnnot set SSL_HANDSHAKE_AS_CLIENT option\n");
  897. goto sslbail;
  898. }
  899. /* Set SSL callback routines. */
  900. secStatus = SSL_GetClientAuthDataHook(sslSocket,
  901. (SSLGetClientAuthData) getClientAuthData,
  902. (void *)certNickname);
  903. if (secStatus != SECSuccess) {
  904. slapi_log_error( SLAPI_LOG_PLUGIN, HTTP_PLUGIN_SUBSYSTEM,
  905. "setupSSLSocket: SSL_GetClientAuthDataHook Failed\n");
  906. goto sslbail;
  907. }
  908. secStatus = SSL_AuthCertificateHook(sslSocket,
  909. (SSLAuthCertificate) authCertificate,
  910. (void *)CERT_GetDefaultCertDB());
  911. if (secStatus != SECSuccess) {
  912. slapi_log_error( SLAPI_LOG_PLUGIN, HTTP_PLUGIN_SUBSYSTEM,
  913. "setupSSLSocket: SSL_AuthCertificateHook Failed\n");
  914. goto sslbail;
  915. }
  916. secStatus = SSL_BadCertHook(sslSocket,
  917. (SSLBadCertHandler) badCertHandler, NULL);
  918. if (secStatus != SECSuccess) {
  919. slapi_log_error( SLAPI_LOG_PLUGIN, HTTP_PLUGIN_SUBSYSTEM,
  920. "setupSSLSocket: SSL_BadCertHook Failed\n");
  921. goto sslbail;
  922. }
  923. secStatus = SSL_HandshakeCallback(sslSocket,
  924. (SSLHandshakeCallback) handshakeCallback, NULL);
  925. if (secStatus != SECSuccess) {
  926. slapi_log_error( SLAPI_LOG_PLUGIN, HTTP_PLUGIN_SUBSYSTEM,
  927. "setupSSLSocket: SSL_HandshakeCallback Failed\n");
  928. goto sslbail;
  929. }
  930. return sslSocket;
  931. sslbail:
  932. PR_Close(fd);
  933. return NULL;
  934. }
  935. SECStatus
  936. authCertificate(void *arg, PRFileDesc *socket,
  937. PRBool checksig, PRBool isServer)
  938. {
  939. SECCertUsage certUsage;
  940. CERTCertificate * cert;
  941. void * pinArg;
  942. char * hostName;
  943. SECStatus secStatus;
  944. if (!arg || !socket) {
  945. slapi_log_error(SLAPI_LOG_PLUGIN, HTTP_PLUGIN_SUBSYSTEM,
  946. " authCertificate: Faulty socket in callback function \n");
  947. return SECFailure;
  948. }
  949. /* Define how the cert is being used based upon the isServer flag. */
  950. certUsage = isServer ? certUsageSSLClient : certUsageSSLServer;
  951. cert = SSL_PeerCertificate(socket);
  952. pinArg = SSL_RevealPinArg(socket);
  953. secStatus = CERT_VerifyCertNow((CERTCertDBHandle *)arg,
  954. cert,
  955. checksig,
  956. certUsage,
  957. pinArg);
  958. /* If this is a server, we're finished. */
  959. if (isServer || secStatus != SECSuccess) {
  960. return secStatus;
  961. }
  962. hostName = SSL_RevealURL(socket);
  963. if (hostName && hostName[0]) {
  964. secStatus = CERT_VerifyCertName(cert, hostName);
  965. } else {
  966. PR_SetError(SSL_ERROR_BAD_CERT_DOMAIN, 0);
  967. secStatus = SECFailure;
  968. }
  969. if (hostName)
  970. PR_Free(hostName);
  971. return secStatus;
  972. }
  973. SECStatus
  974. badCertHandler(void *arg, PRFileDesc *socket)
  975. {
  976. SECStatus secStatus = SECFailure;
  977. PRErrorCode err;
  978. /* log invalid cert here */
  979. if (!arg) {
  980. return secStatus;
  981. }
  982. *(PRErrorCode *)arg = err = PORT_GetError();
  983. switch (err) {
  984. case SEC_ERROR_INVALID_AVA:
  985. case SEC_ERROR_INVALID_TIME:
  986. case SEC_ERROR_BAD_SIGNATURE:
  987. case SEC_ERROR_EXPIRED_CERTIFICATE:
  988. case SEC_ERROR_UNKNOWN_ISSUER:
  989. case SEC_ERROR_UNTRUSTED_CERT:
  990. case SEC_ERROR_CERT_VALID:
  991. case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
  992. case SEC_ERROR_CRL_EXPIRED:
  993. case SEC_ERROR_CRL_BAD_SIGNATURE:
  994. case SEC_ERROR_EXTENSION_VALUE_INVALID:
  995. case SEC_ERROR_CA_CERT_INVALID:
  996. case SEC_ERROR_CERT_USAGES_INVALID:
  997. case SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION:
  998. secStatus = SECSuccess;
  999. break;
  1000. default:
  1001. secStatus = SECFailure;
  1002. break;
  1003. }
  1004. slapi_log_error(SLAPI_LOG_PLUGIN, HTTP_PLUGIN_SUBSYSTEM,
  1005. "Bad certificate: %d\n", err);
  1006. return secStatus;
  1007. }
  1008. SECStatus
  1009. getClientAuthData(void *arg,
  1010. PRFileDesc *socket,
  1011. struct CERTDistNamesStr *caNames,
  1012. struct CERTCertificateStr **pRetCert,
  1013. struct SECKEYPrivateKeyStr **pRetKey)
  1014. {
  1015. CERTCertificate * cert;
  1016. SECKEYPrivateKey * privKey;
  1017. char * chosenNickName = (char *)arg;
  1018. void * proto_win = NULL;
  1019. SECStatus secStatus = SECFailure;
  1020. proto_win = SSL_RevealPinArg(socket);
  1021. if (chosenNickName) {
  1022. cert = PK11_FindCertFromNickname(chosenNickName, proto_win);
  1023. if (cert) {
  1024. privKey = PK11_FindKeyByAnyCert(cert, proto_win);
  1025. if (privKey) {
  1026. secStatus = SECSuccess;
  1027. } else {
  1028. CERT_DestroyCertificate(cert);
  1029. }
  1030. }
  1031. } else { /* no nickname given, automatically find the right cert */
  1032. CERTCertNicknames *names;
  1033. int i;
  1034. names = CERT_GetCertNicknames(CERT_GetDefaultCertDB(),
  1035. SEC_CERT_NICKNAMES_USER, proto_win);
  1036. if (names != NULL) {
  1037. for(i = 0; i < names->numnicknames; i++ ) {
  1038. cert = PK11_FindCertFromNickname(names->nicknames[i],
  1039. proto_win);
  1040. if (!cert) {
  1041. continue;
  1042. }
  1043. /* Only check unexpired certs */
  1044. if (CERT_CheckCertValidTimes(cert, PR_Now(), PR_FALSE)
  1045. != secCertTimeValid ) {
  1046. CERT_DestroyCertificate(cert);
  1047. continue;
  1048. }
  1049. secStatus = NSS_CmpCertChainWCANames(cert, caNames);
  1050. if (secStatus == SECSuccess) {
  1051. privKey = PK11_FindKeyByAnyCert(cert, proto_win);
  1052. if (privKey) {
  1053. break;
  1054. }
  1055. secStatus = SECFailure;
  1056. break;
  1057. }
  1058. CERT_FreeNicknames(names);
  1059. } /* for loop */
  1060. }
  1061. }
  1062. if (secStatus == SECSuccess) {
  1063. *pRetCert = cert;
  1064. *pRetKey = privKey;
  1065. }
  1066. return secStatus;
  1067. }
  1068. SECStatus
  1069. handshakeCallback(PRFileDesc *socket, void *arg)
  1070. {
  1071. slapi_log_error(SLAPI_LOG_PLUGIN, HTTP_PLUGIN_SUBSYSTEM,
  1072. "----------> Handshake has completed, ready to send data securely.\n");
  1073. return SECSuccess;
  1074. }
  1075. /**
  1076. * PUBLIC FUNCTIONS IMPLEMENTATION
  1077. */
  1078. int http_impl_init(Slapi_ComponentId *plugin_id)
  1079. {
  1080. int status = HTTP_IMPL_SUCCESS;
  1081. slapi_log_error(SLAPI_LOG_PLUGIN, HTTP_PLUGIN_SUBSYSTEM,
  1082. "-> http_impl_init \n");
  1083. httpConfig = NULL;
  1084. httpConfig = (httpPluginConfig *) slapi_ch_calloc(1, sizeof(httpPluginConfig));
  1085. status = readConfigLDAPurl(plugin_id, HTTP_PLUGIN_DN);
  1086. if (status != 0) {
  1087. slapi_log_error(SLAPI_LOG_FATAL, HTTP_PLUGIN_SUBSYSTEM,
  1088. "http_impl_start: Unable to get HTTP config information \n");
  1089. return HTTP_IMPL_FAILURE;
  1090. }
  1091. status = readConfigLDAPurl(plugin_id, CONFIG_DN);
  1092. if (status != 0) {
  1093. slapi_log_error(SLAPI_LOG_FATAL, HTTP_PLUGIN_SUBSYSTEM,
  1094. "http_impl_start: Unable to get config information \n");
  1095. return HTTP_IMPL_FAILURE;
  1096. }
  1097. slapi_log_error(SLAPI_LOG_PLUGIN, HTTP_PLUGIN_SUBSYSTEM,
  1098. "<- http_impl_init \n");
  1099. return status;
  1100. }
  1101. int http_impl_get_text(char *url, char **data, int *bytesRead)
  1102. {
  1103. int status = HTTP_IMPL_SUCCESS;
  1104. status = doRequestRetry(url, NULL, NULL, data, bytesRead, HTTP_REQ_TYPE_GET);
  1105. return status;
  1106. }
  1107. int http_impl_get_binary(char *url, char **data, int *bytesRead)
  1108. {
  1109. int status = HTTP_IMPL_SUCCESS;
  1110. status = doRequestRetry(url, NULL, NULL, data, bytesRead, HTTP_REQ_TYPE_GET);
  1111. return status;
  1112. }
  1113. int http_impl_get_redirected_uri(char *url, char **data, int *bytesRead)
  1114. {
  1115. int status = HTTP_IMPL_SUCCESS;
  1116. status = doRequestRetry(url, NULL, NULL, data, bytesRead, HTTP_REQ_TYPE_REDIRECT);
  1117. return status;
  1118. }
  1119. int http_impl_post(char *url, httpheader **httpheaderArray, char *body, char **data, int *bytesRead)
  1120. {
  1121. int status = HTTP_IMPL_SUCCESS;
  1122. status = doRequestRetry(url, httpheaderArray, body, data, bytesRead, HTTP_REQ_TYPE_POST);
  1123. return status;
  1124. }
  1125. void http_impl_shutdown()
  1126. {
  1127. /**
  1128. * Put cleanup code here
  1129. */
  1130. }
  1131. static int readConfigLDAPurl(Slapi_ComponentId *plugin_id, char *plugindn) {
  1132. int rc = LDAP_SUCCESS;
  1133. Slapi_DN *sdn = NULL;
  1134. int status = HTTP_IMPL_SUCCESS;
  1135. Slapi_Entry *entry = NULL;
  1136. sdn = slapi_sdn_new_dn_byref(plugindn);
  1137. rc = slapi_search_internal_get_entry(sdn, NULL, &entry, plugin_id);
  1138. slapi_sdn_free(&sdn);
  1139. if (rc != LDAP_SUCCESS) {
  1140. slapi_log_error( SLAPI_LOG_PLUGIN, HTTP_PLUGIN_SUBSYSTEM,
  1141. "readConfigLDAPurl: Could not find entry %s (error %d)\n", plugindn, rc);
  1142. status = HTTP_IMPL_FAILURE;
  1143. return status;
  1144. }
  1145. if (NULL == entry)
  1146. {
  1147. slapi_log_error( SLAPI_LOG_PLUGIN, HTTP_PLUGIN_SUBSYSTEM,
  1148. "readConfigLDAPurl: No entries found for <%s>\n", plugindn);
  1149. status = HTTP_IMPL_FAILURE;
  1150. return status;
  1151. }
  1152. if ((PL_strcasecmp(plugindn, HTTP_PLUGIN_DN) == 0))
  1153. status = parseHTTPConfigEntry(entry);
  1154. else
  1155. status = parseConfigEntry(entry);
  1156. slapi_entry_free(entry);
  1157. return status;
  1158. }
  1159. /* Retrieves the plugin configuration info */
  1160. /* Retrieves security info as well as the path info required for the SSL
  1161. config dir */
  1162. static int parseConfigEntry(Slapi_Entry *e)
  1163. {
  1164. char *value = NULL;
  1165. value = slapi_entry_attr_get_charptr(e, ATTR_DS_SECURITY);
  1166. if (value) {
  1167. httpConfig->DS_sslOn = value;
  1168. }
  1169. return HTTP_IMPL_SUCCESS;
  1170. }
  1171. static int parseHTTPConfigEntry(Slapi_Entry *e)
  1172. {
  1173. int value = 0;
  1174. value = slapi_entry_attr_get_int(e, ATTR_RETRY_COUNT);
  1175. if (value) {
  1176. httpConfig->retryCount = value;
  1177. }
  1178. value = slapi_entry_attr_get_int(e, ATTR_CONNECTION_TIME_OUT);
  1179. if (value) {
  1180. httpConfig->connectionTimeOut = value;
  1181. }
  1182. else {
  1183. LDAPDebug( LDAP_DEBUG_PLUGIN, "parseHTTPConfigEntry: HTTP Connection Time Out cannot be read. Setting to default value of 5000 ms \n", 0,0,0);
  1184. httpConfig->connectionTimeOut = 5000;
  1185. }
  1186. value = slapi_entry_attr_get_int(e, ATTR_READ_TIME_OUT);
  1187. if (value) {
  1188. httpConfig->readTimeOut = value;
  1189. }
  1190. else {
  1191. LDAPDebug( LDAP_DEBUG_PLUGIN, "parseHTTPConfigEntry: HTTP Read Time Out cannot be read. Setting to default value of 5000 ms \n", 0,0,0);
  1192. httpConfig->readTimeOut = 5000;
  1193. }
  1194. httpConfig->nssInitialized = 0;
  1195. return HTTP_IMPL_SUCCESS;
  1196. }
  1197. /**
  1198. * Self Testing
  1199. */
  1200. #ifdef BUILD_STANDALONE
  1201. int main(int argc, char **argv)
  1202. {
  1203. PRStatus status = PR_SUCCESS;
  1204. char *buf;
  1205. int bytes;
  1206. char *host;
  1207. PRInt32 port;
  1208. char *path;
  1209. if (argc < 2) {
  1210. printf("URL missing\n");
  1211. return -1;
  1212. }
  1213. PR_Init(PR_USER_THREAD,PR_PRIORITY_NORMAL, 0);
  1214. doRequest(argv[1], &buf, &bytes, 2);
  1215. printf( "%s\n", buf );
  1216. return -1;
  1217. }
  1218. #endif