http_impl.c 42 KB

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