1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel (at) haxx.se>, et al. 9 * 10 * This software is licensed as described in the file COPYING, which 11 * you should have received as part of this distribution. The terms 12 * are also available at https://curl.haxx.se/docs/copyright.html. 13 * 14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell 15 * copies of the Software, and permit persons to whom the Software is 16 * furnished to do so, under the terms of the COPYING file. 17 * 18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 * KIND, either express or implied. 20 * 21 ***************************************************************************/ 22 #include "tool_setup.h" 23 24 #ifndef CURL_DISABLE_LIBCURL_OPTION 25 26 #define ENABLE_CURLX_PRINTF 27 /* use our own printf() functions */ 28 #include "curlx.h" 29 30 #include "tool_cfgable.h" 31 #include "tool_easysrc.h" 32 #include "tool_setopt.h" 33 34 #include "memdebug.h" /* keep this as LAST include */ 35 36 /* Lookup tables for converting setopt values back to symbols */ 37 /* For enums, values may be in any order. */ 38 /* For bit masks, put combinations first, then single bits, */ 39 /* and finally any "NONE" value. */ 40 41 #define NV(e) {#e, e} 42 #define NV1(e, v) {#e, (v)} 43 #define NVEND {NULL, 0} /* sentinel to mark end of list */ 44 45 const NameValue setopt_nv_CURLPROXY[] = { 46 NV(CURLPROXY_HTTP), 47 NV(CURLPROXY_HTTP_1_0), 48 NV(CURLPROXY_SOCKS4), 49 NV(CURLPROXY_SOCKS5), 50 NV(CURLPROXY_SOCKS4A), 51 NV(CURLPROXY_SOCKS5_HOSTNAME), 52 NVEND, 53 }; 54 55 const NameValueUnsigned setopt_nv_CURLAUTH[] = { 56 NV(CURLAUTH_ANY), /* combination */ 57 NV(CURLAUTH_ANYSAFE), /* combination */ 58 NV(CURLAUTH_BASIC), 59 NV(CURLAUTH_DIGEST), 60 NV(CURLAUTH_GSSNEGOTIATE), 61 NV(CURLAUTH_NTLM), 62 NV(CURLAUTH_DIGEST_IE), 63 NV(CURLAUTH_NTLM_WB), 64 NV(CURLAUTH_ONLY), 65 NV(CURLAUTH_NONE), 66 NVEND, 67 }; 68 69 const NameValue setopt_nv_CURL_HTTP_VERSION[] = { 70 NV(CURL_HTTP_VERSION_NONE), 71 NV(CURL_HTTP_VERSION_1_0), 72 NV(CURL_HTTP_VERSION_1_1), 73 NV(CURL_HTTP_VERSION_2_0), 74 NV(CURL_HTTP_VERSION_2TLS), 75 NVEND, 76 }; 77 78 const NameValue setopt_nv_CURL_SSLVERSION[] = { 79 NV(CURL_SSLVERSION_DEFAULT), 80 NV(CURL_SSLVERSION_TLSv1), 81 NV(CURL_SSLVERSION_SSLv2), 82 NV(CURL_SSLVERSION_SSLv3), 83 NV(CURL_SSLVERSION_TLSv1_0), 84 NV(CURL_SSLVERSION_TLSv1_1), 85 NV(CURL_SSLVERSION_TLSv1_2), 86 NVEND, 87 }; 88 89 const NameValue setopt_nv_CURL_TIMECOND[] = { 90 NV(CURL_TIMECOND_IFMODSINCE), 91 NV(CURL_TIMECOND_IFUNMODSINCE), 92 NV(CURL_TIMECOND_LASTMOD), 93 NV(CURL_TIMECOND_NONE), 94 NVEND, 95 }; 96 97 const NameValue setopt_nv_CURLFTPSSL_CCC[] = { 98 NV(CURLFTPSSL_CCC_NONE), 99 NV(CURLFTPSSL_CCC_PASSIVE), 100 NV(CURLFTPSSL_CCC_ACTIVE), 101 NVEND, 102 }; 103 104 const NameValue setopt_nv_CURLUSESSL[] = { 105 NV(CURLUSESSL_NONE), 106 NV(CURLUSESSL_TRY), 107 NV(CURLUSESSL_CONTROL), 108 NV(CURLUSESSL_ALL), 109 NVEND, 110 }; 111 112 const NameValueUnsigned setopt_nv_CURLSSLOPT[] = { 113 NV(CURLSSLOPT_ALLOW_BEAST), 114 NV(CURLSSLOPT_NO_REVOKE), 115 NVEND, 116 }; 117 118 const NameValue setopt_nv_CURL_NETRC[] = { 119 NV(CURL_NETRC_IGNORED), 120 NV(CURL_NETRC_OPTIONAL), 121 NV(CURL_NETRC_REQUIRED), 122 NVEND, 123 }; 124 125 /* These mappings essentially triplicated - see 126 * tool_libinfo.c and tool_paramhlp.c */ 127 const NameValue setopt_nv_CURLPROTO[] = { 128 NV(CURLPROTO_ALL), /* combination */ 129 NV(CURLPROTO_DICT), 130 NV(CURLPROTO_FILE), 131 NV(CURLPROTO_FTP), 132 NV(CURLPROTO_FTPS), 133 NV(CURLPROTO_GOPHER), 134 NV(CURLPROTO_HTTP), 135 NV(CURLPROTO_HTTPS), 136 NV(CURLPROTO_IMAP), 137 NV(CURLPROTO_IMAPS), 138 NV(CURLPROTO_LDAP), 139 NV(CURLPROTO_LDAPS), 140 NV(CURLPROTO_POP3), 141 NV(CURLPROTO_POP3S), 142 NV(CURLPROTO_RTSP), 143 NV(CURLPROTO_SCP), 144 NV(CURLPROTO_SFTP), 145 NV(CURLPROTO_SMB), 146 NV(CURLPROTO_SMBS), 147 NV(CURLPROTO_SMTP), 148 NV(CURLPROTO_SMTPS), 149 NV(CURLPROTO_TELNET), 150 NV(CURLPROTO_TFTP), 151 NVEND, 152 }; 153 154 /* These options have non-zero default values. */ 155 static const NameValue setopt_nv_CURLNONZERODEFAULTS[] = { 156 NV1(CURLOPT_SSL_VERIFYPEER, 1), 157 NV1(CURLOPT_SSL_VERIFYHOST, 1), 158 NV1(CURLOPT_SSL_ENABLE_NPN, 1), 159 NV1(CURLOPT_SSL_ENABLE_ALPN, 1), 160 NVEND 161 }; 162 163 /* Format and add code; jump to nomem on malloc error */ 164 #define ADD(args) do { \ 165 ret = easysrc_add args; \ 166 if(ret) \ 167 goto nomem; \ 168 } WHILE_FALSE 169 #define ADDF(args) do { \ 170 ret = easysrc_addf args; \ 171 if(ret) \ 172 goto nomem; \ 173 } WHILE_FALSE 174 175 #define DECL0(s) ADD((&easysrc_decl, s)) 176 #define DECL1(f,a) ADDF((&easysrc_decl, f,a)) 177 178 #define DATA0(s) ADD((&easysrc_data, s)) 179 #define DATA1(f,a) ADDF((&easysrc_data, f,a)) 180 #define DATA2(f,a,b) ADDF((&easysrc_data, f,a,b)) 181 #define DATA3(f,a,b,c) ADDF((&easysrc_data, f,a,b,c)) 182 183 #define CODE0(s) ADD((&easysrc_code, s)) 184 #define CODE1(f,a) ADDF((&easysrc_code, f,a)) 185 #define CODE2(f,a,b) ADDF((&easysrc_code, f,a,b)) 186 #define CODE3(f,a,b,c) ADDF((&easysrc_code, f,a,b,c)) 187 188 #define CLEAN0(s) ADD((&easysrc_clean, s)) 189 #define CLEAN1(f,a) ADDF((&easysrc_clean, f,a)) 190 191 #define REM0(s) ADD((&easysrc_toohard, s)) 192 #define REM1(f,a) ADDF((&easysrc_toohard, f,a)) 193 #define REM2(f,a,b) ADDF((&easysrc_toohard, f,a,b)) 194 195 /* Escape string to C string syntax. Return NULL if out of memory. 196 * Is this correct for those wacky EBCDIC guys? */ 197 static char *c_escape(const char *str) 198 { 199 size_t len = 0; 200 const char *s; 201 unsigned char c; 202 char *escaped, *e; 203 /* Allocate space based on worst-case */ 204 len = strlen(str); 205 escaped = malloc(4 * len + 1); 206 if(!escaped) 207 return NULL; 208 209 e = escaped; 210 for(s=str; (c=*s) != '\0'; s++) { 211 if(c=='\n') { 212 strcpy(e, "\\n"); 213 e += 2; 214 } 215 else if(c=='\r') { 216 strcpy(e, "\\r"); 217 e += 2; 218 } 219 else if(c=='\t') { 220 strcpy(e, "\\t"); 221 e += 2; 222 } 223 else if(c=='\\') { 224 strcpy(e, "\\\\"); 225 e += 2; 226 } 227 else if(c=='"') { 228 strcpy(e, "\\\""); 229 e += 2; 230 } 231 else if(! isprint(c)) { 232 snprintf(e, 5, "\\%03o", (unsigned)c); 233 e += 4; 234 } 235 else 236 *e++ = c; 237 } 238 *e = '\0'; 239 return escaped; 240 } 241 242 /* setopt wrapper for enum types */ 243 CURLcode tool_setopt_enum(CURL *curl, struct GlobalConfig *config, 244 const char *name, CURLoption tag, 245 const NameValue *nvlist, long lval) 246 { 247 CURLcode ret = CURLE_OK; 248 bool skip = FALSE; 249 250 ret = curl_easy_setopt(curl, tag, lval); 251 if(!lval) 252 skip = TRUE; 253 254 if(config->libcurl && !skip && !ret) { 255 /* we only use this for real if --libcurl was used */ 256 const NameValue *nv = NULL; 257 for(nv=nvlist; nv->name; nv++) { 258 if(nv->value == lval) break; /* found it */ 259 } 260 if(! nv->name) { 261 /* If no definition was found, output an explicit value. 262 * This could happen if new values are defined and used 263 * but the NameValue list is not updated. */ 264 CODE2("curl_easy_setopt(hnd, %s, %ldL);", name, lval); 265 } 266 else { 267 CODE2("curl_easy_setopt(hnd, %s, (long)%s);", name, nv->name); 268 } 269 } 270 271 nomem: 272 return ret; 273 } 274 275 /* setopt wrapper for flags */ 276 CURLcode tool_setopt_flags(CURL *curl, struct GlobalConfig *config, 277 const char *name, CURLoption tag, 278 const NameValue *nvlist, long lval) 279 { 280 CURLcode ret = CURLE_OK; 281 bool skip = FALSE; 282 283 ret = curl_easy_setopt(curl, tag, lval); 284 if(!lval) 285 skip = TRUE; 286 287 if(config->libcurl && !skip && !ret) { 288 /* we only use this for real if --libcurl was used */ 289 char preamble[80]; /* should accommodate any symbol name */ 290 long rest = lval; /* bits not handled yet */ 291 const NameValue *nv = NULL; 292 snprintf(preamble, sizeof(preamble), 293 "curl_easy_setopt(hnd, %s, ", name); 294 for(nv=nvlist; nv->name; nv++) { 295 if((nv->value & ~ rest) == 0) { 296 /* all value flags contained in rest */ 297 rest &= ~ nv->value; /* remove bits handled here */ 298 CODE3("%s(long)%s%s", 299 preamble, nv->name, rest ? " |" : ");"); 300 if(!rest) 301 break; /* handled them all */ 302 /* replace with all spaces for continuation line */ 303 snprintf(preamble, sizeof(preamble), "%*s", strlen(preamble), ""); 304 } 305 } 306 /* If any bits have no definition, output an explicit value. 307 * This could happen if new bits are defined and used 308 * but the NameValue list is not updated. */ 309 if(rest) 310 CODE2("%s%ldL);", preamble, rest); 311 } 312 313 nomem: 314 return ret; 315 } 316 317 /* setopt wrapper for bitmasks */ 318 CURLcode tool_setopt_bitmask(CURL *curl, struct GlobalConfig *config, 319 const char *name, CURLoption tag, 320 const NameValueUnsigned *nvlist, 321 long lval) 322 { 323 CURLcode ret = CURLE_OK; 324 bool skip = FALSE; 325 326 ret = curl_easy_setopt(curl, tag, lval); 327 if(!lval) 328 skip = TRUE; 329 330 if(config->libcurl && !skip && !ret) { 331 /* we only use this for real if --libcurl was used */ 332 char preamble[80]; 333 unsigned long rest = (unsigned long)lval; 334 const NameValueUnsigned *nv = NULL; 335 snprintf(preamble, sizeof(preamble), 336 "curl_easy_setopt(hnd, %s, ", name); 337 for(nv=nvlist; nv->name; nv++) { 338 if((nv->value & ~ rest) == 0) { 339 /* all value flags contained in rest */ 340 rest &= ~ nv->value; /* remove bits handled here */ 341 CODE3("%s(long)%s%s", 342 preamble, nv->name, rest ? " |" : ");"); 343 if(!rest) 344 break; /* handled them all */ 345 /* replace with all spaces for continuation line */ 346 snprintf(preamble, sizeof(preamble), "%*s", strlen(preamble), ""); 347 } 348 } 349 /* If any bits have no definition, output an explicit value. 350 * This could happen if new bits are defined and used 351 * but the NameValue list is not updated. */ 352 if(rest) 353 CODE2("%s%luUL);", preamble, rest); 354 } 355 356 nomem: 357 return ret; 358 } 359 360 /* setopt wrapper for CURLOPT_HTTPPOST */ 361 CURLcode tool_setopt_httppost(CURL *curl, struct GlobalConfig *config, 362 const char *name, CURLoption tag, 363 struct curl_httppost *post) 364 { 365 CURLcode ret = CURLE_OK; 366 char *escaped = NULL; 367 bool skip = FALSE; 368 369 ret = curl_easy_setopt(curl, tag, post); 370 if(!post) 371 skip = TRUE; 372 373 if(config->libcurl && !skip && !ret) { 374 struct curl_httppost *pp, *p; 375 int i; 376 /* May use several httppost lists, if multiple POST actions */ 377 i = ++ easysrc_form_count; 378 DECL1("struct curl_httppost *post%d;", i); 379 DATA1("post%d = NULL;", i); 380 CLEAN1("curl_formfree(post%d);", i); 381 CLEAN1("post%d = NULL;", i); 382 if(i == 1) 383 DECL0("struct curl_httppost *postend;"); 384 DATA0("postend = NULL;"); 385 for(p=post; p; p=p->next) { 386 DATA1("curl_formadd(&post%d, &postend,", i); 387 DATA1(" CURLFORM_COPYNAME, \"%s\",", p->name); 388 for(pp=p; pp; pp=pp->more) { 389 /* May be several files uploaded for one name; 390 * these are linked through the 'more' pointer */ 391 Curl_safefree(escaped); 392 escaped = c_escape(pp->contents); 393 if(!escaped) { 394 ret = CURLE_OUT_OF_MEMORY; 395 goto nomem; 396 } 397 if(pp->flags & CURL_HTTPPOST_FILENAME) { 398 /* file upload as for -F @filename */ 399 DATA1(" CURLFORM_FILE, \"%s\",", escaped); 400 } 401 else if(pp->flags & CURL_HTTPPOST_READFILE) { 402 /* content from file as for -F <filename */ 403 DATA1(" CURLFORM_FILECONTENT, \"%s\",", escaped); 404 } 405 else 406 DATA1(" CURLFORM_COPYCONTENTS, \"%s\",", escaped); 407 if(pp->showfilename) { 408 Curl_safefree(escaped); 409 escaped = c_escape(pp->showfilename); 410 if(!escaped) { 411 ret = CURLE_OUT_OF_MEMORY; 412 goto nomem; 413 } 414 DATA1(" CURLFORM_FILENAME, \"%s\",", escaped); 415 } 416 if(pp->contenttype) { 417 Curl_safefree(escaped); 418 escaped = c_escape(pp->contenttype); 419 if(!escaped) { 420 ret = CURLE_OUT_OF_MEMORY; 421 goto nomem; 422 } 423 DATA1(" CURLFORM_CONTENTTYPE, \"%s\",", escaped); 424 } 425 } 426 DATA0(" CURLFORM_END);"); 427 } 428 CODE2("curl_easy_setopt(hnd, %s, post%d);", name, i); 429 } 430 431 nomem: 432 Curl_safefree(escaped); 433 return ret; 434 } 435 436 /* setopt wrapper for curl_slist options */ 437 CURLcode tool_setopt_slist(CURL *curl, struct GlobalConfig *config, 438 const char *name, CURLoption tag, 439 struct curl_slist *list) 440 { 441 CURLcode ret = CURLE_OK; 442 char *escaped = NULL; 443 bool skip = FALSE; 444 445 ret = curl_easy_setopt(curl, tag, list); 446 if(!list) 447 skip = TRUE; 448 449 if(config->libcurl && !skip && !ret) { 450 struct curl_slist *s; 451 int i; 452 /* May need several slist variables, so invent name */ 453 i = ++ easysrc_slist_count; 454 DECL1("struct curl_slist *slist%d;", i); 455 DATA1("slist%d = NULL;", i); 456 CLEAN1("curl_slist_free_all(slist%d);", i); 457 CLEAN1("slist%d = NULL;", i); 458 for(s=list; s; s=s->next) { 459 Curl_safefree(escaped); 460 escaped = c_escape(s->data); 461 if(!escaped) { 462 ret = CURLE_OUT_OF_MEMORY; 463 goto nomem; 464 } 465 DATA3("slist%d = curl_slist_append(slist%d, \"%s\");", i, i, escaped); 466 } 467 CODE2("curl_easy_setopt(hnd, %s, slist%d);", name, i); 468 } 469 470 nomem: 471 Curl_safefree(escaped); 472 return ret; 473 } 474 475 /* generic setopt wrapper for all other options. 476 * Some type information is encoded in the tag value. */ 477 CURLcode tool_setopt(CURL *curl, bool str, struct GlobalConfig *config, 478 const char *name, CURLoption tag, ...) 479 { 480 va_list arg; 481 char buf[256]; 482 const char *value = NULL; 483 bool remark = FALSE; 484 bool skip = FALSE; 485 bool escape = FALSE; 486 char *escaped = NULL; 487 CURLcode ret = CURLE_OK; 488 489 va_start(arg, tag); 490 491 if(tag < CURLOPTTYPE_OBJECTPOINT) { 492 /* Value is expected to be a long */ 493 long lval = va_arg(arg, long); 494 long defval = 0L; 495 const NameValue *nv = NULL; 496 for(nv=setopt_nv_CURLNONZERODEFAULTS; nv->name; nv++) { 497 if(!strcmp(name, nv->name)) { 498 defval = nv->value; 499 break; /* found it */ 500 } 501 } 502 503 snprintf(buf, sizeof(buf), "%ldL", lval); 504 value = buf; 505 ret = curl_easy_setopt(curl, tag, lval); 506 if(lval == defval) 507 skip = TRUE; 508 } 509 else if(tag < CURLOPTTYPE_OFF_T) { 510 /* Value is some sort of object pointer */ 511 void *pval = va_arg(arg, void *); 512 513 /* function pointers are never printable */ 514 if(tag >= CURLOPTTYPE_FUNCTIONPOINT) { 515 if(pval) { 516 value = "functionpointer"; 517 remark = TRUE; 518 } 519 else 520 skip = TRUE; 521 } 522 523 else if(pval && str) { 524 value = (char *)pval; 525 escape = TRUE; 526 } 527 else if(pval) { 528 value = "objectpointer"; 529 remark = TRUE; 530 } 531 else 532 skip = TRUE; 533 534 ret = curl_easy_setopt(curl, tag, pval); 535 536 } 537 else { 538 /* Value is expected to be curl_off_t */ 539 curl_off_t oval = va_arg(arg, curl_off_t); 540 snprintf(buf, sizeof(buf), 541 "(curl_off_t)%" CURL_FORMAT_CURL_OFF_T, oval); 542 value = buf; 543 ret = curl_easy_setopt(curl, tag, oval); 544 545 if(!oval) 546 skip = TRUE; 547 } 548 549 va_end(arg); 550 551 if(config->libcurl && !skip && !ret) { 552 /* we only use this for real if --libcurl was used */ 553 554 if(remark) 555 REM2("%s set to a %s", name, value); 556 else { 557 if(escape) { 558 escaped = c_escape(value); 559 if(!escaped) { 560 ret = CURLE_OUT_OF_MEMORY; 561 goto nomem; 562 } 563 CODE2("curl_easy_setopt(hnd, %s, \"%s\");", name, escaped); 564 } 565 else 566 CODE2("curl_easy_setopt(hnd, %s, %s);", name, value); 567 } 568 } 569 570 nomem: 571 Curl_safefree(escaped); 572 return ret; 573 } 574 575 #endif /* CURL_DISABLE_LIBCURL_OPTION */ 576