Annotation of embedaddon/curl/src/tool_paramhlp.c, revision 1.1
1.1 ! misho 1: /***************************************************************************
! 2: * _ _ ____ _
! 3: * Project ___| | | | _ \| |
! 4: * / __| | | | |_) | |
! 5: * | (__| |_| | _ <| |___
! 6: * \___|\___/|_| \_\_____|
! 7: *
! 8: * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@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: #include "strcase.h"
! 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_getparam.h"
! 32: #include "tool_getpass.h"
! 33: #include "tool_homedir.h"
! 34: #include "tool_msgs.h"
! 35: #include "tool_paramhlp.h"
! 36: #include "tool_version.h"
! 37:
! 38: #include "memdebug.h" /* keep this as LAST include */
! 39:
! 40: struct getout *new_getout(struct OperationConfig *config)
! 41: {
! 42: struct getout *node = calloc(1, sizeof(struct getout));
! 43: struct getout *last = config->url_last;
! 44: if(node) {
! 45: /* append this new node last in the list */
! 46: if(last)
! 47: last->next = node;
! 48: else
! 49: config->url_list = node; /* first node */
! 50:
! 51: /* move the last pointer */
! 52: config->url_last = node;
! 53:
! 54: node->flags = config->default_node_flags;
! 55: }
! 56: return node;
! 57: }
! 58:
! 59: ParameterError file2string(char **bufp, FILE *file)
! 60: {
! 61: char *string = NULL;
! 62: if(file) {
! 63: char *ptr;
! 64: size_t alloc = 512;
! 65: size_t alloc_needed;
! 66: char buffer[256];
! 67: size_t stringlen = 0;
! 68: string = calloc(1, alloc);
! 69: if(!string)
! 70: return PARAM_NO_MEM;
! 71:
! 72: while(fgets(buffer, sizeof(buffer), file)) {
! 73: size_t buflen;
! 74: ptr = strchr(buffer, '\r');
! 75: if(ptr)
! 76: *ptr = '\0';
! 77: ptr = strchr(buffer, '\n');
! 78: if(ptr)
! 79: *ptr = '\0';
! 80: buflen = strlen(buffer);
! 81: alloc_needed = stringlen + buflen + 1;
! 82: if(alloc < alloc_needed) {
! 83: #if SIZEOF_SIZE_T < 8
! 84: if(alloc >= (size_t)SIZE_T_MAX/2) {
! 85: Curl_safefree(string);
! 86: return PARAM_NO_MEM;
! 87: }
! 88: #endif
! 89: /* doubling is enough since the string to add is always max 256 bytes
! 90: and the alloc size start at 512 */
! 91: alloc *= 2;
! 92: ptr = realloc(string, alloc);
! 93: if(!ptr) {
! 94: Curl_safefree(string);
! 95: return PARAM_NO_MEM;
! 96: }
! 97: string = ptr;
! 98: }
! 99: strcpy(string + stringlen, buffer);
! 100: stringlen += buflen;
! 101: }
! 102: }
! 103: *bufp = string;
! 104: return PARAM_OK;
! 105: }
! 106:
! 107: ParameterError file2memory(char **bufp, size_t *size, FILE *file)
! 108: {
! 109: char *newbuf;
! 110: char *buffer = NULL;
! 111: size_t nused = 0;
! 112:
! 113: if(file) {
! 114: size_t nread;
! 115: size_t alloc = 512;
! 116: do {
! 117: if(!buffer || (alloc == nused)) {
! 118: /* size_t overflow detection for huge files */
! 119: if(alloc + 1 > ((size_t)-1)/2) {
! 120: Curl_safefree(buffer);
! 121: return PARAM_NO_MEM;
! 122: }
! 123: alloc *= 2;
! 124: /* allocate an extra char, reserved space, for null termination */
! 125: newbuf = realloc(buffer, alloc + 1);
! 126: if(!newbuf) {
! 127: Curl_safefree(buffer);
! 128: return PARAM_NO_MEM;
! 129: }
! 130: buffer = newbuf;
! 131: }
! 132: nread = fread(buffer + nused, 1, alloc-nused, file);
! 133: nused += nread;
! 134: } while(nread);
! 135: /* null terminate the buffer in case it's used as a string later */
! 136: buffer[nused] = '\0';
! 137: /* free trailing slack space, if possible */
! 138: if(alloc != nused) {
! 139: newbuf = realloc(buffer, nused + 1);
! 140: if(!newbuf) {
! 141: Curl_safefree(buffer);
! 142: return PARAM_NO_MEM;
! 143: }
! 144: buffer = newbuf;
! 145: }
! 146: /* discard buffer if nothing was read */
! 147: if(!nused) {
! 148: Curl_safefree(buffer); /* no string */
! 149: }
! 150: }
! 151: *size = nused;
! 152: *bufp = buffer;
! 153: return PARAM_OK;
! 154: }
! 155:
! 156: void cleanarg(char *str)
! 157: {
! 158: #ifdef HAVE_WRITABLE_ARGV
! 159: /* now that GetStr has copied the contents of nextarg, wipe the next
! 160: * argument out so that the username:password isn't displayed in the
! 161: * system process list */
! 162: if(str) {
! 163: size_t len = strlen(str);
! 164: memset(str, ' ', len);
! 165: }
! 166: #else
! 167: (void)str;
! 168: #endif
! 169: }
! 170:
! 171: /*
! 172: * Parse the string and write the long in the given address. Return PARAM_OK
! 173: * on success, otherwise a parameter specific error enum.
! 174: *
! 175: * Since this function gets called with the 'nextarg' pointer from within the
! 176: * getparameter a lot, we must check it for NULL before accessing the str
! 177: * data.
! 178: */
! 179:
! 180: ParameterError str2num(long *val, const char *str)
! 181: {
! 182: if(str) {
! 183: char *endptr;
! 184: long num;
! 185: errno = 0;
! 186: num = strtol(str, &endptr, 10);
! 187: if(errno == ERANGE)
! 188: return PARAM_NUMBER_TOO_LARGE;
! 189: if((endptr != str) && (endptr == str + strlen(str))) {
! 190: *val = num;
! 191: return PARAM_OK; /* Ok */
! 192: }
! 193: }
! 194: return PARAM_BAD_NUMERIC; /* badness */
! 195: }
! 196:
! 197: /*
! 198: * Parse the string and write the long in the given address. Return PARAM_OK
! 199: * on success, otherwise a parameter error enum. ONLY ACCEPTS POSITIVE NUMBERS!
! 200: *
! 201: * Since this function gets called with the 'nextarg' pointer from within the
! 202: * getparameter a lot, we must check it for NULL before accessing the str
! 203: * data.
! 204: */
! 205:
! 206: ParameterError str2unum(long *val, const char *str)
! 207: {
! 208: ParameterError result = str2num(val, str);
! 209: if(result != PARAM_OK)
! 210: return result;
! 211: if(*val < 0)
! 212: return PARAM_NEGATIVE_NUMERIC;
! 213:
! 214: return PARAM_OK;
! 215: }
! 216:
! 217: /*
! 218: * Parse the string and write the long in the given address if it is below the
! 219: * maximum allowed value. Return PARAM_OK on success, otherwise a parameter
! 220: * error enum. ONLY ACCEPTS POSITIVE NUMBERS!
! 221: *
! 222: * Since this function gets called with the 'nextarg' pointer from within the
! 223: * getparameter a lot, we must check it for NULL before accessing the str
! 224: * data.
! 225: */
! 226:
! 227: ParameterError str2unummax(long *val, const char *str, long max)
! 228: {
! 229: ParameterError result = str2unum(val, str);
! 230: if(result != PARAM_OK)
! 231: return result;
! 232: if(*val > max)
! 233: return PARAM_NUMBER_TOO_LARGE;
! 234:
! 235: return PARAM_OK;
! 236: }
! 237:
! 238:
! 239: /*
! 240: * Parse the string and write the double in the given address. Return PARAM_OK
! 241: * on success, otherwise a parameter specific error enum.
! 242: *
! 243: * The 'max' argument is the maximum value allowed, as the numbers are often
! 244: * multiplied when later used.
! 245: *
! 246: * Since this function gets called with the 'nextarg' pointer from within the
! 247: * getparameter a lot, we must check it for NULL before accessing the str
! 248: * data.
! 249: */
! 250:
! 251: static ParameterError str2double(double *val, const char *str, long max)
! 252: {
! 253: if(str) {
! 254: char *endptr;
! 255: double num;
! 256: errno = 0;
! 257: num = strtod(str, &endptr);
! 258: if(errno == ERANGE)
! 259: return PARAM_NUMBER_TOO_LARGE;
! 260: if(num > max) {
! 261: /* too large */
! 262: return PARAM_NUMBER_TOO_LARGE;
! 263: }
! 264: if((endptr != str) && (endptr == str + strlen(str))) {
! 265: *val = num;
! 266: return PARAM_OK; /* Ok */
! 267: }
! 268: }
! 269: return PARAM_BAD_NUMERIC; /* badness */
! 270: }
! 271:
! 272: /*
! 273: * Parse the string and write the double in the given address. Return PARAM_OK
! 274: * on success, otherwise a parameter error enum. ONLY ACCEPTS POSITIVE NUMBERS!
! 275: *
! 276: * The 'max' argument is the maximum value allowed, as the numbers are often
! 277: * multiplied when later used.
! 278: *
! 279: * Since this function gets called with the 'nextarg' pointer from within the
! 280: * getparameter a lot, we must check it for NULL before accessing the str
! 281: * data.
! 282: */
! 283:
! 284: ParameterError str2udouble(double *valp, const char *str, long max)
! 285: {
! 286: double value;
! 287: ParameterError result = str2double(&value, str, max);
! 288: if(result != PARAM_OK)
! 289: return result;
! 290: if(value < 0)
! 291: return PARAM_NEGATIVE_NUMERIC;
! 292:
! 293: *valp = value;
! 294: return PARAM_OK;
! 295: }
! 296:
! 297: /*
! 298: * Parse the string and modify the long in the given address. Return
! 299: * non-zero on failure, zero on success.
! 300: *
! 301: * The string is a list of protocols
! 302: *
! 303: * Since this function gets called with the 'nextarg' pointer from within the
! 304: * getparameter a lot, we must check it for NULL before accessing the str
! 305: * data.
! 306: */
! 307:
! 308: long proto2num(struct OperationConfig *config, long *val, const char *str)
! 309: {
! 310: char *buffer;
! 311: const char *sep = ",";
! 312: char *token;
! 313:
! 314: static struct sprotos {
! 315: const char *name;
! 316: long bit;
! 317: } const protos[] = {
! 318: { "all", CURLPROTO_ALL },
! 319: { "http", CURLPROTO_HTTP },
! 320: { "https", CURLPROTO_HTTPS },
! 321: { "ftp", CURLPROTO_FTP },
! 322: { "ftps", CURLPROTO_FTPS },
! 323: { "scp", CURLPROTO_SCP },
! 324: { "sftp", CURLPROTO_SFTP },
! 325: { "telnet", CURLPROTO_TELNET },
! 326: { "ldap", CURLPROTO_LDAP },
! 327: { "ldaps", CURLPROTO_LDAPS },
! 328: { "dict", CURLPROTO_DICT },
! 329: { "file", CURLPROTO_FILE },
! 330: { "tftp", CURLPROTO_TFTP },
! 331: { "imap", CURLPROTO_IMAP },
! 332: { "imaps", CURLPROTO_IMAPS },
! 333: { "pop3", CURLPROTO_POP3 },
! 334: { "pop3s", CURLPROTO_POP3S },
! 335: { "smtp", CURLPROTO_SMTP },
! 336: { "smtps", CURLPROTO_SMTPS },
! 337: { "rtsp", CURLPROTO_RTSP },
! 338: { "gopher", CURLPROTO_GOPHER },
! 339: { "smb", CURLPROTO_SMB },
! 340: { "smbs", CURLPROTO_SMBS },
! 341: { NULL, 0 }
! 342: };
! 343:
! 344: if(!str)
! 345: return 1;
! 346:
! 347: buffer = strdup(str); /* because strtok corrupts it */
! 348: if(!buffer)
! 349: return 1;
! 350:
! 351: /* Allow strtok() here since this isn't used threaded */
! 352: /* !checksrc! disable BANNEDFUNC 2 */
! 353: for(token = strtok(buffer, sep);
! 354: token;
! 355: token = strtok(NULL, sep)) {
! 356: enum e_action { allow, deny, set } action = allow;
! 357:
! 358: struct sprotos const *pp;
! 359:
! 360: /* Process token modifiers */
! 361: while(!ISALNUM(*token)) { /* may be NULL if token is all modifiers */
! 362: switch (*token++) {
! 363: case '=':
! 364: action = set;
! 365: break;
! 366: case '-':
! 367: action = deny;
! 368: break;
! 369: case '+':
! 370: action = allow;
! 371: break;
! 372: default: /* Includes case of terminating NULL */
! 373: Curl_safefree(buffer);
! 374: return 1;
! 375: }
! 376: }
! 377:
! 378: for(pp = protos; pp->name; pp++) {
! 379: if(curl_strequal(token, pp->name)) {
! 380: switch(action) {
! 381: case deny:
! 382: *val &= ~(pp->bit);
! 383: break;
! 384: case allow:
! 385: *val |= pp->bit;
! 386: break;
! 387: case set:
! 388: *val = pp->bit;
! 389: break;
! 390: }
! 391: break;
! 392: }
! 393: }
! 394:
! 395: if(!(pp->name)) { /* unknown protocol */
! 396: /* If they have specified only this protocol, we say treat it as
! 397: if no protocols are allowed */
! 398: if(action == set)
! 399: *val = 0;
! 400: warnf(config->global, "unrecognized protocol '%s'\n", token);
! 401: }
! 402: }
! 403: Curl_safefree(buffer);
! 404: return 0;
! 405: }
! 406:
! 407: /**
! 408: * Check if the given string is a protocol supported by libcurl
! 409: *
! 410: * @param str the protocol name
! 411: * @return PARAM_OK protocol supported
! 412: * @return PARAM_LIBCURL_UNSUPPORTED_PROTOCOL protocol not supported
! 413: * @return PARAM_REQUIRES_PARAMETER missing parameter
! 414: */
! 415: int check_protocol(const char *str)
! 416: {
! 417: const char * const *pp;
! 418: const curl_version_info_data *curlinfo = curl_version_info(CURLVERSION_NOW);
! 419: if(!str)
! 420: return PARAM_REQUIRES_PARAMETER;
! 421: for(pp = curlinfo->protocols; *pp; pp++) {
! 422: if(curl_strequal(*pp, str))
! 423: return PARAM_OK;
! 424: }
! 425: return PARAM_LIBCURL_UNSUPPORTED_PROTOCOL;
! 426: }
! 427:
! 428: /**
! 429: * Parses the given string looking for an offset (which may be a
! 430: * larger-than-integer value). The offset CANNOT be negative!
! 431: *
! 432: * @param val the offset to populate
! 433: * @param str the buffer containing the offset
! 434: * @return PARAM_OK if successful, a parameter specific error enum if failure.
! 435: */
! 436: ParameterError str2offset(curl_off_t *val, const char *str)
! 437: {
! 438: char *endptr;
! 439: if(str[0] == '-')
! 440: /* offsets aren't negative, this indicates weird input */
! 441: return PARAM_NEGATIVE_NUMERIC;
! 442:
! 443: #if(SIZEOF_CURL_OFF_T > SIZEOF_LONG)
! 444: {
! 445: CURLofft offt = curlx_strtoofft(str, &endptr, 0, val);
! 446: if(CURL_OFFT_FLOW == offt)
! 447: return PARAM_NUMBER_TOO_LARGE;
! 448: else if(CURL_OFFT_INVAL == offt)
! 449: return PARAM_BAD_NUMERIC;
! 450: }
! 451: #else
! 452: errno = 0;
! 453: *val = strtol(str, &endptr, 0);
! 454: if((*val == LONG_MIN || *val == LONG_MAX) && errno == ERANGE)
! 455: return PARAM_NUMBER_TOO_LARGE;
! 456: #endif
! 457: if((endptr != str) && (endptr == str + strlen(str)))
! 458: return PARAM_OK;
! 459:
! 460: return PARAM_BAD_NUMERIC;
! 461: }
! 462:
! 463: static CURLcode checkpasswd(const char *kind, /* for what purpose */
! 464: const size_t i, /* operation index */
! 465: const bool last, /* TRUE if last operation */
! 466: char **userpwd) /* pointer to allocated string */
! 467: {
! 468: char *psep;
! 469: char *osep;
! 470:
! 471: if(!*userpwd)
! 472: return CURLE_OK;
! 473:
! 474: /* Attempt to find the password separator */
! 475: psep = strchr(*userpwd, ':');
! 476:
! 477: /* Attempt to find the options separator */
! 478: osep = strchr(*userpwd, ';');
! 479:
! 480: if(!psep && **userpwd != ';') {
! 481: /* no password present, prompt for one */
! 482: char passwd[256] = "";
! 483: char prompt[256];
! 484: size_t passwdlen;
! 485: size_t userlen = strlen(*userpwd);
! 486: char *passptr;
! 487:
! 488: if(osep)
! 489: *osep = '\0';
! 490:
! 491: /* build a nice-looking prompt */
! 492: if(!i && last)
! 493: curlx_msnprintf(prompt, sizeof(prompt),
! 494: "Enter %s password for user '%s':",
! 495: kind, *userpwd);
! 496: else
! 497: curlx_msnprintf(prompt, sizeof(prompt),
! 498: "Enter %s password for user '%s' on URL #%zu:",
! 499: kind, *userpwd, i + 1);
! 500:
! 501: /* get password */
! 502: getpass_r(prompt, passwd, sizeof(passwd));
! 503: passwdlen = strlen(passwd);
! 504:
! 505: if(osep)
! 506: *osep = ';';
! 507:
! 508: /* extend the allocated memory area to fit the password too */
! 509: passptr = realloc(*userpwd,
! 510: passwdlen + 1 + /* an extra for the colon */
! 511: userlen + 1); /* an extra for the zero */
! 512: if(!passptr)
! 513: return CURLE_OUT_OF_MEMORY;
! 514:
! 515: /* append the password separated with a colon */
! 516: passptr[userlen] = ':';
! 517: memcpy(&passptr[userlen + 1], passwd, passwdlen + 1);
! 518: *userpwd = passptr;
! 519: }
! 520:
! 521: return CURLE_OK;
! 522: }
! 523:
! 524: ParameterError add2list(struct curl_slist **list, const char *ptr)
! 525: {
! 526: struct curl_slist *newlist = curl_slist_append(*list, ptr);
! 527: if(newlist)
! 528: *list = newlist;
! 529: else
! 530: return PARAM_NO_MEM;
! 531:
! 532: return PARAM_OK;
! 533: }
! 534:
! 535: int ftpfilemethod(struct OperationConfig *config, const char *str)
! 536: {
! 537: if(curl_strequal("singlecwd", str))
! 538: return CURLFTPMETHOD_SINGLECWD;
! 539: if(curl_strequal("nocwd", str))
! 540: return CURLFTPMETHOD_NOCWD;
! 541: if(curl_strequal("multicwd", str))
! 542: return CURLFTPMETHOD_MULTICWD;
! 543:
! 544: warnf(config->global, "unrecognized ftp file method '%s', using default\n",
! 545: str);
! 546:
! 547: return CURLFTPMETHOD_MULTICWD;
! 548: }
! 549:
! 550: int ftpcccmethod(struct OperationConfig *config, const char *str)
! 551: {
! 552: if(curl_strequal("passive", str))
! 553: return CURLFTPSSL_CCC_PASSIVE;
! 554: if(curl_strequal("active", str))
! 555: return CURLFTPSSL_CCC_ACTIVE;
! 556:
! 557: warnf(config->global, "unrecognized ftp CCC method '%s', using default\n",
! 558: str);
! 559:
! 560: return CURLFTPSSL_CCC_PASSIVE;
! 561: }
! 562:
! 563: long delegation(struct OperationConfig *config, const char *str)
! 564: {
! 565: if(curl_strequal("none", str))
! 566: return CURLGSSAPI_DELEGATION_NONE;
! 567: if(curl_strequal("policy", str))
! 568: return CURLGSSAPI_DELEGATION_POLICY_FLAG;
! 569: if(curl_strequal("always", str))
! 570: return CURLGSSAPI_DELEGATION_FLAG;
! 571:
! 572: warnf(config->global, "unrecognized delegation method '%s', using none\n",
! 573: str);
! 574:
! 575: return CURLGSSAPI_DELEGATION_NONE;
! 576: }
! 577:
! 578: /*
! 579: * my_useragent: returns allocated string with default user agent
! 580: */
! 581: static char *my_useragent(void)
! 582: {
! 583: return strdup(CURL_NAME "/" CURL_VERSION);
! 584: }
! 585:
! 586: CURLcode get_args(struct OperationConfig *config, const size_t i)
! 587: {
! 588: CURLcode result = CURLE_OK;
! 589: bool last = (config->next ? FALSE : TRUE);
! 590:
! 591: /* Check we have a password for the given host user */
! 592: if(config->userpwd && !config->oauth_bearer) {
! 593: result = checkpasswd("host", i, last, &config->userpwd);
! 594: if(result)
! 595: return result;
! 596: }
! 597:
! 598: /* Check we have a password for the given proxy user */
! 599: if(config->proxyuserpwd) {
! 600: result = checkpasswd("proxy", i, last, &config->proxyuserpwd);
! 601: if(result)
! 602: return result;
! 603: }
! 604:
! 605: /* Check we have a user agent */
! 606: if(!config->useragent) {
! 607: config->useragent = my_useragent();
! 608: if(!config->useragent) {
! 609: errorf(config->global, "out of memory\n");
! 610: result = CURLE_OUT_OF_MEMORY;
! 611: }
! 612: }
! 613:
! 614: return result;
! 615: }
! 616:
! 617: /*
! 618: * Parse the string and modify ssl_version in the val argument. Return PARAM_OK
! 619: * on success, otherwise a parameter error enum. ONLY ACCEPTS POSITIVE NUMBERS!
! 620: *
! 621: * Since this function gets called with the 'nextarg' pointer from within the
! 622: * getparameter a lot, we must check it for NULL before accessing the str
! 623: * data.
! 624: */
! 625:
! 626: ParameterError str2tls_max(long *val, const char *str)
! 627: {
! 628: static struct s_tls_max {
! 629: const char *tls_max_str;
! 630: long tls_max;
! 631: } const tls_max_array[] = {
! 632: { "default", CURL_SSLVERSION_MAX_DEFAULT },
! 633: { "1.0", CURL_SSLVERSION_MAX_TLSv1_0 },
! 634: { "1.1", CURL_SSLVERSION_MAX_TLSv1_1 },
! 635: { "1.2", CURL_SSLVERSION_MAX_TLSv1_2 },
! 636: { "1.3", CURL_SSLVERSION_MAX_TLSv1_3 }
! 637: };
! 638: size_t i = 0;
! 639: if(!str)
! 640: return PARAM_REQUIRES_PARAMETER;
! 641: for(i = 0; i < sizeof(tls_max_array)/sizeof(tls_max_array[0]); i++) {
! 642: if(!strcmp(str, tls_max_array[i].tls_max_str)) {
! 643: *val = tls_max_array[i].tls_max;
! 644: return PARAM_OK;
! 645: }
! 646: }
! 647: return PARAM_BAD_USE;
! 648: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>