ocrc.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. /* Copyright 2009, UCAR/Unidata and OPeNDAP, Inc.
  2. See the COPYRIGHT file for more information. */
  3. #include "config.h"
  4. #ifdef HAVE_UNISTD_H
  5. #include <unistd.h>
  6. #endif
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include "ocinternal.h"
  11. #include "ocdebug.h"
  12. #include "ocdata.h"
  13. #include "occontent.h"
  14. #include "oclog.h"
  15. #include "ocrc.h"
  16. #define RTAG ']'
  17. #define LTAG '['
  18. #define TRIMCHARS " \t\r\n"
  19. #define TRIM(x) rctrimright(rctrimleft((x),TRIMCHARS),TRIMCHARS)
  20. #define HTTPPREFIXDEPRECATED "CURL."
  21. #define HTTPPREFIX "HTTP."
  22. /* the .dodsrc triple store */
  23. struct OCTriplestore* ocdodsrc = NULL;
  24. static int parseproxy(OCstate* state, char* v);
  25. static int rcreadline(FILE* f, char* more, int morelen);
  26. static char* rctrimright(char* more, char* trimchars);
  27. static char* rctrimleft(char* more, char* trimchars);
  28. static void ocdodsrcdump(char* msg, struct OCTriple*, int ntriples);
  29. static char* curllookup(char* suffix,char* url);
  30. /* The Username and password are in the URL if the URL is of the form:
  31. * http://<name>:<passwd>@<host>/....
  32. */
  33. int
  34. occredentials_in_url(const char *url)
  35. {
  36. char *pos = strstr(url, "http://");
  37. if (!pos)
  38. return 0;
  39. pos += 7;
  40. if (strchr(pos, '@') && strchr(pos, ':'))
  41. return 1;
  42. return 0;
  43. }
  44. int
  45. ocextract_credentials(const char *url, char **name, char **pw, char **result_url)
  46. {
  47. char *pos;
  48. char *end;
  49. char *middle;
  50. int up_len = 0;
  51. int mid_len = 0;
  52. int midpas_len = 0;
  53. int url_len = 0;
  54. if (strchr(url, '@')) {
  55. pos = strstr(url, "http://");
  56. if (pos)
  57. pos += 7;
  58. middle = strchr(pos, ':');
  59. mid_len = middle - pos;
  60. *name = malloc(sizeof(char) * (mid_len + 1));
  61. strncpy(*name, pos, mid_len);
  62. (*name)[mid_len] = '\0';
  63. if (middle)
  64. middle += 1;
  65. end = strchr(middle, '@');
  66. midpas_len = end - middle;
  67. *pw = malloc(sizeof(char) * (midpas_len + 1));
  68. strncpy(*pw, middle, midpas_len);
  69. (*pw)[midpas_len] = '\0';
  70. up_len = end - pos;
  71. url_len = strlen(url) - up_len;
  72. *result_url = malloc(sizeof(char) * (url_len + 1));
  73. if (!result_url)
  74. return OC_ENOMEM;
  75. strncpy(*result_url, url, pos - url);
  76. strncpy(*result_url + (pos - url), end + 1, url_len - (pos - url));
  77. #if 0
  78. fprintf(stderr, "URL without username and password: %s:%d\n", sURL, url_len );
  79. fprintf(stderr, "URL username and password: %s:%d\n", sUP, up_len);
  80. fprintf(stderr, "URL username: %s:%d\n", sUser, mid_len);
  81. fprintf(stderr, "URL password: %s:%d\n", sPassword, midpas_len);
  82. #endif
  83. (*result_url)[url_len] = '\0';
  84. return OC_NOERR;
  85. }
  86. else {
  87. return OC_EIO;
  88. }
  89. }
  90. static int
  91. rcreadline(FILE* f, char* more, int morelen)
  92. {
  93. int i = 0;
  94. int c = getc(f);
  95. if(c < 0) return 0;
  96. for(;;) {
  97. if(i < morelen) /* ignore excess characters */
  98. more[i++]=c;
  99. c = getc(f);
  100. if(c < 0) break; /* eof */
  101. if(c == '\n') break; /* eol */
  102. }
  103. /* null terminate more */
  104. more[i] = '\0';
  105. return 1;
  106. }
  107. /* Trim specified characters from front/left */
  108. static char*
  109. rctrimleft(char* more, char* trimchars)
  110. {
  111. char* p = more;
  112. int c;
  113. while((c=*p) != '\0') {if(strchr(trimchars,c) != NULL) p++; else break;}
  114. return p;
  115. }
  116. /* Trim specified characters from end/right */
  117. static char*
  118. rctrimright(char* more, char* trimchars)
  119. {
  120. int len = strlen(more);
  121. char* p = more + (len - 1);
  122. while(p != more) {if(strchr(trimchars,*p) != NULL) p--; else break;}
  123. /* null terminate */
  124. p[1] = '\0';
  125. return more;
  126. }
  127. static int
  128. parseproxy(OCstate* state, char* v)
  129. {
  130. char *host_pos = NULL;
  131. char *port_pos = NULL;
  132. if(strlen(v) == 0) return OC_NOERR; /* nothing there*/
  133. if (occredentials_in_url(v)) {
  134. char *result_url = NULL;
  135. ocextract_credentials(v, &state->creds.username,
  136. &state->creds.password,
  137. &result_url);
  138. v = result_url;
  139. }
  140. /* allocating a bit more than likely needed ... */
  141. host_pos = strstr(v, "http://");
  142. if (host_pos)
  143. host_pos += strlen("http://");
  144. else
  145. host_pos = v;
  146. port_pos = strchr(host_pos, ':');
  147. if (port_pos) {
  148. int host_len;
  149. char *port_sep = port_pos;
  150. port_pos++;
  151. *port_sep = '\0';
  152. host_len = strlen(host_pos);
  153. state->proxy.host = malloc(sizeof(char) * host_len + 1);
  154. if (!state->proxy.host)
  155. return OC_ENOMEM;
  156. strncpy(state->proxy.host, host_pos, host_len);
  157. state->proxy.host[host_len + 1] = '\0';
  158. state->proxy.port = atoi(port_pos);
  159. } else {
  160. int host_len = strlen(host_pos);
  161. state->proxy.host = malloc(sizeof(char) * host_len + 1);
  162. if (!state->proxy.host)
  163. return OC_ENOMEM;
  164. strncpy(state->proxy.host, host_pos, host_len);
  165. state->proxy.host[host_len + 1] = '\0';
  166. state->proxy.port = 80;
  167. }
  168. #if 0
  169. state->proxy.host[v_len] = '\0';
  170. state->proxy.port = atoi(v);
  171. s_len = strlen(v);
  172. state->proxy.user = malloc(sizeof(char) * s_len + 1);
  173. if (!state->proxy.user)
  174. return OC_ENOMEM;
  175. strncpy(state->proxy.user, v, s_len);
  176. state->proxy.user[s_len] = '\0';
  177. p_len = strlen(v);
  178. state->proxy.password = malloc(sizeof(char) * p_len + 1);
  179. if (!state->proxy.password)
  180. return OC_ENOMEM;
  181. strncpy(state->proxy.password, v, p_len);
  182. state->proxy.password[p_len] = '\0';
  183. #endif /*0*/
  184. if (ocdebug > 1) {
  185. oc_log(LOGNOTE,"host name: %s", state->proxy.host);
  186. oc_log(LOGNOTE,"user name: %s", state->creds.username);
  187. #ifdef INSECURE
  188. oc_log(LOGNOTE,"password: %s", state->creds.password);
  189. #endif
  190. oc_log(LOGNOTE,"port number: %d", state->proxy.port);
  191. }
  192. if(v) free(v);
  193. return OC_NOERR;
  194. }
  195. /* insertion sort the triplestore based on url */
  196. static void
  197. sorttriplestore(void)
  198. {
  199. int i, nsorted;
  200. struct OCTriple* sorted = NULL;
  201. if(ocdodsrc->ntriples <= 1) return; /* nothing to sort */
  202. if(ocdebug > 2)
  203. ocdodsrcdump("initial:",ocdodsrc->triples,ocdodsrc->ntriples);
  204. sorted = (struct OCTriple*)malloc(sizeof(struct OCTriple)*ocdodsrc->ntriples);
  205. if(sorted == NULL) {
  206. oc_log(LOGERR,"sorttriplestore: out of memory");
  207. return;
  208. }
  209. nsorted = 0;
  210. while(nsorted < ocdodsrc->ntriples) {
  211. int largest;
  212. /* locate first non killed entry */
  213. for(largest=0;largest<ocdodsrc->ntriples;largest++) {
  214. if(ocdodsrc->triples[largest].key[0] != '\0') break;
  215. }
  216. OCASSERT(ocdodsrc->triples[largest].key[0] != '\0');
  217. for(i=0;i<ocdodsrc->ntriples;i++) {
  218. if(ocdodsrc->triples[i].key[0] != '\0') { /* avoid empty slots */
  219. int lexorder = strcmp(ocdodsrc->triples[i].url,ocdodsrc->triples[largest].url);
  220. int leni = strlen(ocdodsrc->triples[i].url);
  221. int lenlarge = strlen(ocdodsrc->triples[largest].url);
  222. /* this defines the ordering */
  223. if(leni == 0 && lenlarge == 0) continue; /* if no urls, then leave in order */
  224. if(leni != 0 && lenlarge == 0) largest = i;
  225. else if(lexorder > 0) largest = i;
  226. }
  227. }
  228. /* Move the largest entry */
  229. OCASSERT(ocdodsrc->triples[largest].key[0] != 0);
  230. sorted[nsorted] = ocdodsrc->triples[largest];
  231. ocdodsrc->triples[largest].key[0] = '\0'; /* kill entry */
  232. nsorted++;
  233. if(ocdebug > 2)
  234. ocdodsrcdump("pass:",sorted,nsorted);
  235. }
  236. memcpy((void*)ocdodsrc->triples,(void*)sorted,sizeof(struct OCTriple)*nsorted);
  237. free(sorted);
  238. if(ocdebug > 0)
  239. ocdodsrcdump("final .dodsrc order:",ocdodsrc->triples,ocdodsrc->ntriples);
  240. }
  241. /* Create a triple store from a file */
  242. int
  243. ocdodsrc_read(char* basename, char* path)
  244. {
  245. char line0[MAXRCLINESIZE];
  246. FILE *in_file = NULL;
  247. int linecount = 0;
  248. if(ocdodsrc == NULL) {
  249. ocdodsrc = (struct OCTriplestore*)malloc(sizeof(struct OCTriplestore));
  250. if(ocdodsrc == NULL) {
  251. oc_log(LOGERR,"ocdodsrc_read: out of memory");
  252. return 0;
  253. }
  254. }
  255. ocdodsrc->ntriples = 0;
  256. in_file = fopen(path, "r"); /* Open the file to read it */
  257. if (in_file == NULL) {
  258. oc_log(LOGERR, "Could not open configuration file: %s",basename);
  259. return OC_EPERM;
  260. }
  261. for(;;) {
  262. char *line,*key,*value;
  263. if(!rcreadline(in_file,line0,sizeof(line0))) break;
  264. linecount++;
  265. if(linecount >= MAXRCLINES) {
  266. oc_log(LOGERR, ".dodsrc has too many lines");
  267. return 0;
  268. }
  269. line = line0;
  270. /* check for comment */
  271. if (line[0] == '#') continue;
  272. /* trim leading blanks */
  273. line = rctrimleft(line,TRIMCHARS);
  274. if(strlen(line) >= MAXRCLINESIZE) {
  275. oc_log(LOGERR, "%s line too long: %s",basename,line0);
  276. return 0;
  277. }
  278. /* parse the line */
  279. ocdodsrc->triples[ocdodsrc->ntriples].url[0] = '\0'; /*assume no url*/
  280. if(line[0] == LTAG) {
  281. char* url = ++line;
  282. char* rtag = strchr(line,RTAG);
  283. if(rtag == NULL) {
  284. oc_log(LOGERR, "Malformed [url] in %s entry: %s",basename,line);
  285. continue;
  286. }
  287. line = rtag + 1;
  288. *rtag = '\0';
  289. /* trim again */
  290. line = rctrimleft(line,TRIMCHARS);
  291. /* save the url */
  292. strcpy(ocdodsrc->triples[ocdodsrc->ntriples].url,TRIM(url));
  293. }
  294. if(strlen(line)==0) continue; /* empty line */
  295. /* split off key and value */
  296. key=line;
  297. value = strchr(line, '=');
  298. if(value == NULL) {
  299. /* add fake '=1' */
  300. if(strlen(line) + strlen("=1") >= MAXRCLINESIZE) {
  301. oc_log(LOGERR, "%s entry too long: %s",basename,line);
  302. continue;
  303. }
  304. strcat(line,"=1");
  305. value = strchr(line,'=');
  306. }
  307. *value = '\0';
  308. value++;
  309. strcpy(ocdodsrc->triples[ocdodsrc->ntriples].key,TRIM(key));
  310. strcpy(ocdodsrc->triples[ocdodsrc->ntriples].value,TRIM(value));
  311. ocdodsrc->ntriples++;
  312. }
  313. fclose(in_file);
  314. sorttriplestore();
  315. return 1;
  316. }
  317. int
  318. ocdodsrc_process(OCstate* state)
  319. {
  320. int stat = 0;
  321. char* value;
  322. char* url = ocuribuild(state->uri,NULL,NULL,OCURIENCODE);
  323. if(ocdodsrc == NULL) goto done;
  324. value = curllookup("DEFLATE",url);
  325. if(value != NULL) {
  326. if(atoi(value)) state->curlflags.compress = 1;
  327. if(ocdebug > 0)
  328. oc_log(LOGNOTE,"Compression: %ld", state->curlflags.compress);
  329. }
  330. if((value = curllookup("VERBOSE",url)) != NULL) {
  331. if(atoi(value)) state->curlflags.verbose = 1;
  332. if(ocdebug > 0)
  333. oc_log(LOGNOTE,"curl.verbose: %ld", state->curlflags.verbose);
  334. }
  335. if((value = curllookup("TIMEOUT",url)) != NULL) {
  336. if(atoi(value)) state->curlflags.timeout = atoi(value);
  337. if(ocdebug > 0)
  338. oc_log(LOGNOTE,"curl.timeout: %ld", state->curlflags.timeout);
  339. }
  340. if((value = curllookup("COOKIEFILE",url)) != NULL) {
  341. state->curlflags.cookiefile = strdup(TRIM(value));
  342. if(!state->curlflags.cookiefile) {stat = OC_ENOMEM; goto done;}
  343. if(ocdebug > 0)
  344. oc_log(LOGNOTE,"COOKIEFILE: %s", state->curlflags.cookiefile);
  345. }
  346. if((value = curllookup("COOKIEJAR",url))
  347. || (value = curllookup("COOKIE_JAR",url))) {
  348. state->curlflags.cookiejar = strdup(TRIM(value));
  349. if(!state->curlflags.cookiejar) {stat = OC_ENOMEM; goto done;}
  350. if(ocdebug > 0)
  351. oc_log(LOGNOTE,"COOKIEJAR: %s", state->curlflags.cookiejar);
  352. }
  353. /* Some servers (e.g. thredds) appear to require a place
  354. to put cookies in order for some security functions to work
  355. */
  356. if(state->curlflags.cookiejar == NULL
  357. && state->curlflags.cookiefile == NULL) {
  358. state->curlflags.cookiefile = strdup("");
  359. }
  360. if((value = curllookup("PROXY_SERVER",url)) != NULL) {
  361. stat = parseproxy(state,TRIM(value));
  362. if(stat != OC_NOERR) goto done;
  363. }
  364. if((value = curllookup("SSL.VALIDATE",url)) != NULL) {
  365. if(atoi(value)) state->ssl.validate = 1;
  366. if(ocdebug > 0)
  367. oc_log(LOGNOTE,"CURL.SSL.VALIDATE: %ld", state->ssl.validate);
  368. }
  369. if((value = curllookup("SSL.CERTIFICATE",url)) != NULL) {
  370. state->ssl.certificate = strdup(TRIM(value));
  371. if(!state->ssl.certificate) {stat = OC_ENOMEM; goto done;}
  372. if(ocdebug > 0)
  373. oc_log(LOGNOTE,"CREDENTIALS.SSL.CERTIFICATE: %s", state->ssl.certificate);
  374. }
  375. if((value = curllookup("SSL.KEY",url)) != NULL) {
  376. state->ssl.key = strdup(TRIM(value));
  377. if(!state->ssl.key) {stat = OC_ENOMEM; goto done;}
  378. if(ocdebug > 0)
  379. oc_log(LOGNOTE,"CREDENTIALS.SSL.KEY: %s", state->ssl.key);
  380. }
  381. if((value = curllookup("SSL.KEYPASSWORD",url)) != NULL) {
  382. state->ssl.keypasswd = strdup(TRIM(value));
  383. if(!state->ssl.keypasswd) {stat = OC_ENOMEM; goto done;}
  384. #ifdef INSECURE
  385. if(ocdebug > 0)
  386. oc_log(LOGNOTE,"CREDENTIALS.SSL.KEYPASSWORD: %s", state->ssl.keypasswd);
  387. #endif
  388. }
  389. if((value = curllookup("SSL.CAINFO",url)) != NULL) {
  390. state->ssl.cainfo = strdup(TRIM(value));
  391. if(!state->ssl.cainfo) {stat = OC_ENOMEM; goto done;}
  392. if(ocdebug > 0)
  393. oc_log(LOGNOTE,"SSL.CAINFO: %s", state->ssl.cainfo);
  394. }
  395. if((value = curllookup("SSL.CAPATH",url)) != NULL) {
  396. state->ssl.capath = strdup(TRIM(value));
  397. if(!state->ssl.capath) {stat = OC_ENOMEM; goto done;}
  398. if(ocdebug > 0)
  399. oc_log(LOGNOTE,"SSL.CAPATH: %s", state->ssl.capath);
  400. }
  401. if((value = curllookup("SSL.VERIFYPEER",url)) != NULL) {
  402. char* s = strdup(TRIM(value));
  403. int tf = 0;
  404. if(s == NULL || strcmp(s,"0")==0 || strcasecmp(s,"false")==0)
  405. tf = 0;
  406. else if(strcmp(s,"1")==0 || strcasecmp(s,"true")==0)
  407. tf = 1;
  408. else
  409. tf = 1; /* default if not null */
  410. state->ssl.verifypeer = tf;
  411. if(ocdebug > 0)
  412. oc_log(LOGNOTE,"SSL.VERIFYPEER: %d", state->ssl.verifypeer);
  413. }
  414. if((value = curllookup("CREDENTIALS.USER",url)) != NULL) {
  415. state->creds.username = strdup(TRIM(value));
  416. if(!state->creds.username) {stat = OC_ENOMEM; goto done;}
  417. if(ocdebug > 0)
  418. oc_log(LOGNOTE,"CREDENTIALS.USER: %s", state->creds.username);
  419. }
  420. if((value = curllookup("CREDENTIALS.PASSWORD",url)) != NULL) {
  421. state->creds.password = strdup(TRIM(value));
  422. if(!state->creds.password) {stat = OC_ENOMEM; goto done;}
  423. }
  424. /* else ignore */
  425. done:
  426. if(url != NULL) free(url);
  427. return stat;
  428. }
  429. char*
  430. ocdodsrc_lookup(char* key, char* url)
  431. {
  432. int i,found;
  433. struct OCTriple* triple = ocdodsrc->triples;
  434. if(key == NULL || ocdodsrc == NULL) return NULL;
  435. if(url == NULL) url = "";
  436. /* Assume that the triple store has been properly sorted */
  437. for(found=0,i=0;i<ocdodsrc->ntriples;i++,triple++) {
  438. int triplelen = strlen(triple->url);
  439. int t;
  440. if(strcmp(key,triple->key) != 0) continue; /* keys do not match */
  441. /* If the triple entry has no url, then use it (because we have checked all other cases)*/
  442. if(triplelen == 0) {found=1;break;}
  443. /* do url prefix comparison */
  444. t = ocstrncmp(url,triple->url,triplelen);
  445. if(t == 0) {found=1; break;}
  446. }
  447. if(ocdebug > 2)
  448. {
  449. if(found) {
  450. fprintf(stderr,"lookup %s: [%s]%s = %s\n",url,triple->url,triple->key,triple->value);
  451. }
  452. }
  453. return (found ? triple->value : NULL);
  454. }
  455. static void
  456. ocdodsrcdump(char* msg, struct OCTriple* triples, int ntriples)
  457. {
  458. int i;
  459. if(msg != NULL) fprintf(stderr,"%s\n",msg);
  460. if(ocdodsrc == NULL) {
  461. fprintf(stderr,"<EMPTY>\n");
  462. return;
  463. }
  464. if(triples == NULL) triples= ocdodsrc->triples;
  465. if(ntriples < 0 ) ntriples= ocdodsrc->ntriples;
  466. for(i=0;i<ntriples;i++) {
  467. fprintf(stderr,"\t%s\t%s\t%s\n",
  468. (strlen(triples[i].url)==0?"--":triples[i].url),
  469. triples[i].key,
  470. triples[i].value);
  471. }
  472. }
  473. /* Isolate the "CURL." prefix to allow changing to something else */
  474. static char*
  475. curllookup(char* suffix, char* url)
  476. {
  477. char key[2048];
  478. char* value = NULL;
  479. strcpy(key,HTTPPREFIX);
  480. strcat(key,suffix);
  481. value = ocdodsrc_lookup(key,url);
  482. if(value == NULL) {
  483. strcpy(key,HTTPPREFIXDEPRECATED);
  484. strcat(key,suffix);
  485. value = ocdodsrc_lookup(key,url);
  486. }
  487. return value;
  488. }