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