113498266Sopenharmony_ci/***************************************************************************
213498266Sopenharmony_ci *                                  _   _ ____  _
313498266Sopenharmony_ci *  Project                     ___| | | |  _ \| |
413498266Sopenharmony_ci *                             / __| | | | |_) | |
513498266Sopenharmony_ci *                            | (__| |_| |  _ <| |___
613498266Sopenharmony_ci *                             \___|\___/|_| \_\_____|
713498266Sopenharmony_ci *
813498266Sopenharmony_ci * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
913498266Sopenharmony_ci *
1013498266Sopenharmony_ci * This software is licensed as described in the file COPYING, which
1113498266Sopenharmony_ci * you should have received as part of this distribution. The terms
1213498266Sopenharmony_ci * are also available at https://curl.se/docs/copyright.html.
1313498266Sopenharmony_ci *
1413498266Sopenharmony_ci * You may opt to use, copy, modify, merge, publish, distribute and/or sell
1513498266Sopenharmony_ci * copies of the Software, and permit persons to whom the Software is
1613498266Sopenharmony_ci * furnished to do so, under the terms of the COPYING file.
1713498266Sopenharmony_ci *
1813498266Sopenharmony_ci * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
1913498266Sopenharmony_ci * KIND, either express or implied.
2013498266Sopenharmony_ci *
2113498266Sopenharmony_ci * SPDX-License-Identifier: curl
2213498266Sopenharmony_ci *
2313498266Sopenharmony_ci ***************************************************************************/
2413498266Sopenharmony_ci#include "tool_setup.h"
2513498266Sopenharmony_ci
2613498266Sopenharmony_ci#include "strcase.h"
2713498266Sopenharmony_ci
2813498266Sopenharmony_ci#define ENABLE_CURLX_PRINTF
2913498266Sopenharmony_ci/* use our own printf() functions */
3013498266Sopenharmony_ci#include "curlx.h"
3113498266Sopenharmony_ci
3213498266Sopenharmony_ci#include "tool_cfgable.h"
3313498266Sopenharmony_ci#include "tool_getparam.h"
3413498266Sopenharmony_ci#include "tool_getpass.h"
3513498266Sopenharmony_ci#include "tool_msgs.h"
3613498266Sopenharmony_ci#include "tool_paramhlp.h"
3713498266Sopenharmony_ci#include "tool_libinfo.h"
3813498266Sopenharmony_ci#include "tool_util.h"
3913498266Sopenharmony_ci#include "tool_version.h"
4013498266Sopenharmony_ci#include "dynbuf.h"
4113498266Sopenharmony_ci
4213498266Sopenharmony_ci#include "memdebug.h" /* keep this as LAST include */
4313498266Sopenharmony_ci
4413498266Sopenharmony_cistruct getout *new_getout(struct OperationConfig *config)
4513498266Sopenharmony_ci{
4613498266Sopenharmony_ci  struct getout *node = calloc(1, sizeof(struct getout));
4713498266Sopenharmony_ci  struct getout *last = config->url_last;
4813498266Sopenharmony_ci  if(node) {
4913498266Sopenharmony_ci    static int outnum = 0;
5013498266Sopenharmony_ci
5113498266Sopenharmony_ci    /* append this new node last in the list */
5213498266Sopenharmony_ci    if(last)
5313498266Sopenharmony_ci      last->next = node;
5413498266Sopenharmony_ci    else
5513498266Sopenharmony_ci      config->url_list = node; /* first node */
5613498266Sopenharmony_ci
5713498266Sopenharmony_ci    /* move the last pointer */
5813498266Sopenharmony_ci    config->url_last = node;
5913498266Sopenharmony_ci
6013498266Sopenharmony_ci    node->flags = config->default_node_flags;
6113498266Sopenharmony_ci    node->num = outnum++;
6213498266Sopenharmony_ci  }
6313498266Sopenharmony_ci  return node;
6413498266Sopenharmony_ci}
6513498266Sopenharmony_ci
6613498266Sopenharmony_ci#define MAX_FILE2STRING (256*1024*1024) /* big enough ? */
6713498266Sopenharmony_ci
6813498266Sopenharmony_ciParameterError file2string(char **bufp, FILE *file)
6913498266Sopenharmony_ci{
7013498266Sopenharmony_ci  struct curlx_dynbuf dyn;
7113498266Sopenharmony_ci  DEBUGASSERT(MAX_FILE2STRING < INT_MAX); /* needs to fit in an int later */
7213498266Sopenharmony_ci  curlx_dyn_init(&dyn, MAX_FILE2STRING);
7313498266Sopenharmony_ci  if(file) {
7413498266Sopenharmony_ci    char buffer[256];
7513498266Sopenharmony_ci
7613498266Sopenharmony_ci    while(fgets(buffer, sizeof(buffer), file)) {
7713498266Sopenharmony_ci      char *ptr = strchr(buffer, '\r');
7813498266Sopenharmony_ci      if(ptr)
7913498266Sopenharmony_ci        *ptr = '\0';
8013498266Sopenharmony_ci      ptr = strchr(buffer, '\n');
8113498266Sopenharmony_ci      if(ptr)
8213498266Sopenharmony_ci        *ptr = '\0';
8313498266Sopenharmony_ci      if(curlx_dyn_add(&dyn, buffer))
8413498266Sopenharmony_ci        return PARAM_NO_MEM;
8513498266Sopenharmony_ci    }
8613498266Sopenharmony_ci  }
8713498266Sopenharmony_ci  *bufp = curlx_dyn_ptr(&dyn);
8813498266Sopenharmony_ci  return PARAM_OK;
8913498266Sopenharmony_ci}
9013498266Sopenharmony_ci
9113498266Sopenharmony_ciParameterError file2memory(char **bufp, size_t *size, FILE *file)
9213498266Sopenharmony_ci{
9313498266Sopenharmony_ci  if(file) {
9413498266Sopenharmony_ci    size_t nread;
9513498266Sopenharmony_ci    struct curlx_dynbuf dyn;
9613498266Sopenharmony_ci    /* The size needs to fit in an int later */
9713498266Sopenharmony_ci    DEBUGASSERT(MAX_FILE2MEMORY < INT_MAX);
9813498266Sopenharmony_ci    curlx_dyn_init(&dyn, MAX_FILE2MEMORY);
9913498266Sopenharmony_ci    do {
10013498266Sopenharmony_ci      char buffer[4096];
10113498266Sopenharmony_ci      nread = fread(buffer, 1, sizeof(buffer), file);
10213498266Sopenharmony_ci      if(ferror(file)) {
10313498266Sopenharmony_ci        curlx_dyn_free(&dyn);
10413498266Sopenharmony_ci        *size = 0;
10513498266Sopenharmony_ci        *bufp = NULL;
10613498266Sopenharmony_ci        return PARAM_READ_ERROR;
10713498266Sopenharmony_ci      }
10813498266Sopenharmony_ci      if(nread)
10913498266Sopenharmony_ci        if(curlx_dyn_addn(&dyn, buffer, nread))
11013498266Sopenharmony_ci          return PARAM_NO_MEM;
11113498266Sopenharmony_ci    } while(!feof(file));
11213498266Sopenharmony_ci    *size = curlx_dyn_len(&dyn);
11313498266Sopenharmony_ci    *bufp = curlx_dyn_ptr(&dyn);
11413498266Sopenharmony_ci  }
11513498266Sopenharmony_ci  else {
11613498266Sopenharmony_ci    *size = 0;
11713498266Sopenharmony_ci    *bufp = NULL;
11813498266Sopenharmony_ci  }
11913498266Sopenharmony_ci  return PARAM_OK;
12013498266Sopenharmony_ci}
12113498266Sopenharmony_ci
12213498266Sopenharmony_ci/*
12313498266Sopenharmony_ci * Parse the string and write the long in the given address. Return PARAM_OK
12413498266Sopenharmony_ci * on success, otherwise a parameter specific error enum.
12513498266Sopenharmony_ci *
12613498266Sopenharmony_ci * Since this function gets called with the 'nextarg' pointer from within the
12713498266Sopenharmony_ci * getparameter a lot, we must check it for NULL before accessing the str
12813498266Sopenharmony_ci * data.
12913498266Sopenharmony_ci */
13013498266Sopenharmony_cistatic ParameterError getnum(long *val, const char *str, int base)
13113498266Sopenharmony_ci{
13213498266Sopenharmony_ci  if(str) {
13313498266Sopenharmony_ci    char *endptr = NULL;
13413498266Sopenharmony_ci    long num;
13513498266Sopenharmony_ci    if(!str[0])
13613498266Sopenharmony_ci      return PARAM_BLANK_STRING;
13713498266Sopenharmony_ci    errno = 0;
13813498266Sopenharmony_ci    num = strtol(str, &endptr, base);
13913498266Sopenharmony_ci    if(errno == ERANGE)
14013498266Sopenharmony_ci      return PARAM_NUMBER_TOO_LARGE;
14113498266Sopenharmony_ci    if((endptr != str) && (*endptr == '\0')) {
14213498266Sopenharmony_ci      *val = num;
14313498266Sopenharmony_ci      return PARAM_OK;  /* Ok */
14413498266Sopenharmony_ci    }
14513498266Sopenharmony_ci  }
14613498266Sopenharmony_ci  return PARAM_BAD_NUMERIC; /* badness */
14713498266Sopenharmony_ci}
14813498266Sopenharmony_ci
14913498266Sopenharmony_ciParameterError str2num(long *val, const char *str)
15013498266Sopenharmony_ci{
15113498266Sopenharmony_ci  return getnum(val, str, 10);
15213498266Sopenharmony_ci}
15313498266Sopenharmony_ci
15413498266Sopenharmony_ciParameterError oct2nummax(long *val, const char *str, long max)
15513498266Sopenharmony_ci{
15613498266Sopenharmony_ci  ParameterError result = getnum(val, str, 8);
15713498266Sopenharmony_ci  if(result != PARAM_OK)
15813498266Sopenharmony_ci    return result;
15913498266Sopenharmony_ci  else if(*val > max)
16013498266Sopenharmony_ci    return PARAM_NUMBER_TOO_LARGE;
16113498266Sopenharmony_ci  else if(*val < 0)
16213498266Sopenharmony_ci    return PARAM_NEGATIVE_NUMERIC;
16313498266Sopenharmony_ci
16413498266Sopenharmony_ci  return PARAM_OK;
16513498266Sopenharmony_ci}
16613498266Sopenharmony_ci
16713498266Sopenharmony_ci/*
16813498266Sopenharmony_ci * Parse the string and write the long in the given address. Return PARAM_OK
16913498266Sopenharmony_ci * on success, otherwise a parameter error enum. ONLY ACCEPTS POSITIVE NUMBERS!
17013498266Sopenharmony_ci *
17113498266Sopenharmony_ci * Since this function gets called with the 'nextarg' pointer from within the
17213498266Sopenharmony_ci * getparameter a lot, we must check it for NULL before accessing the str
17313498266Sopenharmony_ci * data.
17413498266Sopenharmony_ci */
17513498266Sopenharmony_ci
17613498266Sopenharmony_ciParameterError str2unum(long *val, const char *str)
17713498266Sopenharmony_ci{
17813498266Sopenharmony_ci  ParameterError result = getnum(val, str, 10);
17913498266Sopenharmony_ci  if(result != PARAM_OK)
18013498266Sopenharmony_ci    return result;
18113498266Sopenharmony_ci  if(*val < 0)
18213498266Sopenharmony_ci    return PARAM_NEGATIVE_NUMERIC;
18313498266Sopenharmony_ci
18413498266Sopenharmony_ci  return PARAM_OK;
18513498266Sopenharmony_ci}
18613498266Sopenharmony_ci
18713498266Sopenharmony_ci/*
18813498266Sopenharmony_ci * Parse the string and write the long in the given address if it is below the
18913498266Sopenharmony_ci * maximum allowed value. Return PARAM_OK on success, otherwise a parameter
19013498266Sopenharmony_ci * error enum. ONLY ACCEPTS POSITIVE NUMBERS!
19113498266Sopenharmony_ci *
19213498266Sopenharmony_ci * Since this function gets called with the 'nextarg' pointer from within the
19313498266Sopenharmony_ci * getparameter a lot, we must check it for NULL before accessing the str
19413498266Sopenharmony_ci * data.
19513498266Sopenharmony_ci */
19613498266Sopenharmony_ci
19713498266Sopenharmony_ciParameterError str2unummax(long *val, const char *str, long max)
19813498266Sopenharmony_ci{
19913498266Sopenharmony_ci  ParameterError result = str2unum(val, str);
20013498266Sopenharmony_ci  if(result != PARAM_OK)
20113498266Sopenharmony_ci    return result;
20213498266Sopenharmony_ci  if(*val > max)
20313498266Sopenharmony_ci    return PARAM_NUMBER_TOO_LARGE;
20413498266Sopenharmony_ci
20513498266Sopenharmony_ci  return PARAM_OK;
20613498266Sopenharmony_ci}
20713498266Sopenharmony_ci
20813498266Sopenharmony_ci
20913498266Sopenharmony_ci/*
21013498266Sopenharmony_ci * Parse the string and write the double in the given address. Return PARAM_OK
21113498266Sopenharmony_ci * on success, otherwise a parameter specific error enum.
21213498266Sopenharmony_ci *
21313498266Sopenharmony_ci * The 'max' argument is the maximum value allowed, as the numbers are often
21413498266Sopenharmony_ci * multiplied when later used.
21513498266Sopenharmony_ci *
21613498266Sopenharmony_ci * Since this function gets called with the 'nextarg' pointer from within the
21713498266Sopenharmony_ci * getparameter a lot, we must check it for NULL before accessing the str
21813498266Sopenharmony_ci * data.
21913498266Sopenharmony_ci */
22013498266Sopenharmony_ci
22113498266Sopenharmony_cistatic ParameterError str2double(double *val, const char *str, double max)
22213498266Sopenharmony_ci{
22313498266Sopenharmony_ci  if(str) {
22413498266Sopenharmony_ci    char *endptr;
22513498266Sopenharmony_ci    double num;
22613498266Sopenharmony_ci    errno = 0;
22713498266Sopenharmony_ci    num = strtod(str, &endptr);
22813498266Sopenharmony_ci    if(errno == ERANGE)
22913498266Sopenharmony_ci      return PARAM_NUMBER_TOO_LARGE;
23013498266Sopenharmony_ci    if(num > max) {
23113498266Sopenharmony_ci      /* too large */
23213498266Sopenharmony_ci      return PARAM_NUMBER_TOO_LARGE;
23313498266Sopenharmony_ci    }
23413498266Sopenharmony_ci    if((endptr != str) && (endptr == str + strlen(str))) {
23513498266Sopenharmony_ci      *val = num;
23613498266Sopenharmony_ci      return PARAM_OK;  /* Ok */
23713498266Sopenharmony_ci    }
23813498266Sopenharmony_ci  }
23913498266Sopenharmony_ci  return PARAM_BAD_NUMERIC; /* badness */
24013498266Sopenharmony_ci}
24113498266Sopenharmony_ci
24213498266Sopenharmony_ci/*
24313498266Sopenharmony_ci * Parse the string as seconds with decimals, and write the number of
24413498266Sopenharmony_ci * milliseconds that corresponds in the given address. Return PARAM_OK on
24513498266Sopenharmony_ci * success, otherwise a parameter error enum. ONLY ACCEPTS POSITIVE NUMBERS!
24613498266Sopenharmony_ci *
24713498266Sopenharmony_ci * The 'max' argument is the maximum value allowed, as the numbers are often
24813498266Sopenharmony_ci * multiplied when later used.
24913498266Sopenharmony_ci *
25013498266Sopenharmony_ci * Since this function gets called with the 'nextarg' pointer from within the
25113498266Sopenharmony_ci * getparameter a lot, we must check it for NULL before accessing the str
25213498266Sopenharmony_ci * data.
25313498266Sopenharmony_ci */
25413498266Sopenharmony_ci
25513498266Sopenharmony_ciParameterError secs2ms(long *valp, const char *str)
25613498266Sopenharmony_ci{
25713498266Sopenharmony_ci  double value;
25813498266Sopenharmony_ci  ParameterError result = str2double(&value, str, (double)LONG_MAX/1000);
25913498266Sopenharmony_ci  if(result != PARAM_OK)
26013498266Sopenharmony_ci    return result;
26113498266Sopenharmony_ci  if(value < 0)
26213498266Sopenharmony_ci    return PARAM_NEGATIVE_NUMERIC;
26313498266Sopenharmony_ci
26413498266Sopenharmony_ci  *valp = (long)(value*1000);
26513498266Sopenharmony_ci  return PARAM_OK;
26613498266Sopenharmony_ci}
26713498266Sopenharmony_ci
26813498266Sopenharmony_ci/*
26913498266Sopenharmony_ci * Implement protocol sets in null-terminated array of protocol name pointers.
27013498266Sopenharmony_ci */
27113498266Sopenharmony_ci
27213498266Sopenharmony_ci/* Return index of prototype token in set, card(set) if not found.
27313498266Sopenharmony_ci   Can be called with proto == NULL to get card(set). */
27413498266Sopenharmony_cistatic size_t protoset_index(const char * const *protoset, const char *proto)
27513498266Sopenharmony_ci{
27613498266Sopenharmony_ci  const char * const *p = protoset;
27713498266Sopenharmony_ci
27813498266Sopenharmony_ci  DEBUGASSERT(proto == proto_token(proto));     /* Ensure it is tokenized. */
27913498266Sopenharmony_ci
28013498266Sopenharmony_ci  for(; *p; p++)
28113498266Sopenharmony_ci    if(proto == *p)
28213498266Sopenharmony_ci      break;
28313498266Sopenharmony_ci  return p - protoset;
28413498266Sopenharmony_ci}
28513498266Sopenharmony_ci
28613498266Sopenharmony_ci/* Include protocol token in set. */
28713498266Sopenharmony_cistatic void protoset_set(const char **protoset, const char *proto)
28813498266Sopenharmony_ci{
28913498266Sopenharmony_ci  if(proto) {
29013498266Sopenharmony_ci    size_t n = protoset_index(protoset, proto);
29113498266Sopenharmony_ci
29213498266Sopenharmony_ci    if(!protoset[n]) {
29313498266Sopenharmony_ci      DEBUGASSERT(n < proto_count);
29413498266Sopenharmony_ci      protoset[n] = proto;
29513498266Sopenharmony_ci      protoset[n + 1] = NULL;
29613498266Sopenharmony_ci    }
29713498266Sopenharmony_ci  }
29813498266Sopenharmony_ci}
29913498266Sopenharmony_ci
30013498266Sopenharmony_ci/* Exclude protocol token from set. */
30113498266Sopenharmony_cistatic void protoset_clear(const char **protoset, const char *proto)
30213498266Sopenharmony_ci{
30313498266Sopenharmony_ci  if(proto) {
30413498266Sopenharmony_ci    size_t n = protoset_index(protoset, proto);
30513498266Sopenharmony_ci
30613498266Sopenharmony_ci    if(protoset[n]) {
30713498266Sopenharmony_ci      size_t m = protoset_index(protoset, NULL) - 1;
30813498266Sopenharmony_ci
30913498266Sopenharmony_ci      protoset[n] = protoset[m];
31013498266Sopenharmony_ci      protoset[m] = NULL;
31113498266Sopenharmony_ci    }
31213498266Sopenharmony_ci  }
31313498266Sopenharmony_ci}
31413498266Sopenharmony_ci
31513498266Sopenharmony_ci/*
31613498266Sopenharmony_ci * Parse the string and provide an allocated libcurl compatible protocol
31713498266Sopenharmony_ci * string output. Return non-zero on failure, zero on success.
31813498266Sopenharmony_ci *
31913498266Sopenharmony_ci * The string is a list of protocols
32013498266Sopenharmony_ci *
32113498266Sopenharmony_ci * Since this function gets called with the 'nextarg' pointer from within the
32213498266Sopenharmony_ci * getparameter a lot, we must check it for NULL before accessing the str
32313498266Sopenharmony_ci * data.
32413498266Sopenharmony_ci */
32513498266Sopenharmony_ci
32613498266Sopenharmony_ci#define MAX_PROTOSTRING (64*11) /* Enough room for 64 10-chars proto names. */
32713498266Sopenharmony_ci
32813498266Sopenharmony_ciParameterError proto2num(struct OperationConfig *config,
32913498266Sopenharmony_ci                         const char * const *val, char **ostr, const char *str)
33013498266Sopenharmony_ci{
33113498266Sopenharmony_ci  char *buffer;
33213498266Sopenharmony_ci  const char *sep = ",";
33313498266Sopenharmony_ci  char *token;
33413498266Sopenharmony_ci  const char **protoset;
33513498266Sopenharmony_ci  struct curlx_dynbuf obuf;
33613498266Sopenharmony_ci  size_t proto;
33713498266Sopenharmony_ci  CURLcode result;
33813498266Sopenharmony_ci
33913498266Sopenharmony_ci  curlx_dyn_init(&obuf, MAX_PROTOSTRING);
34013498266Sopenharmony_ci
34113498266Sopenharmony_ci  if(!str)
34213498266Sopenharmony_ci    return PARAM_OPTION_AMBIGUOUS;
34313498266Sopenharmony_ci
34413498266Sopenharmony_ci  buffer = strdup(str); /* because strtok corrupts it */
34513498266Sopenharmony_ci  if(!buffer)
34613498266Sopenharmony_ci    return PARAM_NO_MEM;
34713498266Sopenharmony_ci
34813498266Sopenharmony_ci  protoset = malloc((proto_count + 1) * sizeof(*protoset));
34913498266Sopenharmony_ci  if(!protoset) {
35013498266Sopenharmony_ci    free(buffer);
35113498266Sopenharmony_ci    return PARAM_NO_MEM;
35213498266Sopenharmony_ci  }
35313498266Sopenharmony_ci
35413498266Sopenharmony_ci  /* Preset protocol set with default values. */
35513498266Sopenharmony_ci  protoset[0] = NULL;
35613498266Sopenharmony_ci  for(; *val; val++) {
35713498266Sopenharmony_ci    const char *p = proto_token(*val);
35813498266Sopenharmony_ci
35913498266Sopenharmony_ci    if(p)
36013498266Sopenharmony_ci      protoset_set(protoset, p);
36113498266Sopenharmony_ci  }
36213498266Sopenharmony_ci
36313498266Sopenharmony_ci  /* Allow strtok() here since this isn't used threaded */
36413498266Sopenharmony_ci  /* !checksrc! disable BANNEDFUNC 2 */
36513498266Sopenharmony_ci  for(token = strtok(buffer, sep);
36613498266Sopenharmony_ci      token;
36713498266Sopenharmony_ci      token = strtok(NULL, sep)) {
36813498266Sopenharmony_ci    enum e_action { allow, deny, set } action = allow;
36913498266Sopenharmony_ci
37013498266Sopenharmony_ci    /* Process token modifiers */
37113498266Sopenharmony_ci    while(!ISALNUM(*token)) { /* may be NULL if token is all modifiers */
37213498266Sopenharmony_ci      switch(*token++) {
37313498266Sopenharmony_ci      case '=':
37413498266Sopenharmony_ci        action = set;
37513498266Sopenharmony_ci        break;
37613498266Sopenharmony_ci      case '-':
37713498266Sopenharmony_ci        action = deny;
37813498266Sopenharmony_ci        break;
37913498266Sopenharmony_ci      case '+':
38013498266Sopenharmony_ci        action = allow;
38113498266Sopenharmony_ci        break;
38213498266Sopenharmony_ci      default: /* Includes case of terminating NULL */
38313498266Sopenharmony_ci        free(buffer);
38413498266Sopenharmony_ci        free((char *) protoset);
38513498266Sopenharmony_ci        return PARAM_BAD_USE;
38613498266Sopenharmony_ci      }
38713498266Sopenharmony_ci    }
38813498266Sopenharmony_ci
38913498266Sopenharmony_ci    if(curl_strequal(token, "all")) {
39013498266Sopenharmony_ci      switch(action) {
39113498266Sopenharmony_ci      case deny:
39213498266Sopenharmony_ci        protoset[0] = NULL;
39313498266Sopenharmony_ci        break;
39413498266Sopenharmony_ci      case allow:
39513498266Sopenharmony_ci      case set:
39613498266Sopenharmony_ci        memcpy((char *) protoset,
39713498266Sopenharmony_ci               built_in_protos, (proto_count + 1) * sizeof(*protoset));
39813498266Sopenharmony_ci        break;
39913498266Sopenharmony_ci      }
40013498266Sopenharmony_ci    }
40113498266Sopenharmony_ci    else {
40213498266Sopenharmony_ci      const char *p = proto_token(token);
40313498266Sopenharmony_ci
40413498266Sopenharmony_ci      if(p)
40513498266Sopenharmony_ci        switch(action) {
40613498266Sopenharmony_ci        case deny:
40713498266Sopenharmony_ci          protoset_clear(protoset, p);
40813498266Sopenharmony_ci          break;
40913498266Sopenharmony_ci        case set:
41013498266Sopenharmony_ci          protoset[0] = NULL;
41113498266Sopenharmony_ci          FALLTHROUGH();
41213498266Sopenharmony_ci        case allow:
41313498266Sopenharmony_ci          protoset_set(protoset, p);
41413498266Sopenharmony_ci          break;
41513498266Sopenharmony_ci        }
41613498266Sopenharmony_ci      else { /* unknown protocol */
41713498266Sopenharmony_ci        /* If they have specified only this protocol, we say treat it as
41813498266Sopenharmony_ci           if no protocols are allowed */
41913498266Sopenharmony_ci        if(action == set)
42013498266Sopenharmony_ci          protoset[0] = NULL;
42113498266Sopenharmony_ci        warnf(config->global, "unrecognized protocol '%s'", token);
42213498266Sopenharmony_ci      }
42313498266Sopenharmony_ci    }
42413498266Sopenharmony_ci  }
42513498266Sopenharmony_ci  free(buffer);
42613498266Sopenharmony_ci
42713498266Sopenharmony_ci  /* We need the protocols in alphabetic order for CI tests requirements. */
42813498266Sopenharmony_ci  qsort((char *) protoset, protoset_index(protoset, NULL), sizeof(*protoset),
42913498266Sopenharmony_ci        struplocompare4sort);
43013498266Sopenharmony_ci
43113498266Sopenharmony_ci  result = curlx_dyn_addn(&obuf, "", 0);
43213498266Sopenharmony_ci  for(proto = 0; protoset[proto] && !result; proto++)
43313498266Sopenharmony_ci    result = curlx_dyn_addf(&obuf, "%s,", protoset[proto]);
43413498266Sopenharmony_ci  free((char *) protoset);
43513498266Sopenharmony_ci  curlx_dyn_setlen(&obuf, curlx_dyn_len(&obuf) - 1);
43613498266Sopenharmony_ci  free(*ostr);
43713498266Sopenharmony_ci  *ostr = curlx_dyn_ptr(&obuf);
43813498266Sopenharmony_ci
43913498266Sopenharmony_ci  return *ostr ? PARAM_OK : PARAM_NO_MEM;
44013498266Sopenharmony_ci}
44113498266Sopenharmony_ci
44213498266Sopenharmony_ci/**
44313498266Sopenharmony_ci * Check if the given string is a protocol supported by libcurl
44413498266Sopenharmony_ci *
44513498266Sopenharmony_ci * @param str  the protocol name
44613498266Sopenharmony_ci * @return PARAM_OK  protocol supported
44713498266Sopenharmony_ci * @return PARAM_LIBCURL_UNSUPPORTED_PROTOCOL  protocol not supported
44813498266Sopenharmony_ci * @return PARAM_REQUIRES_PARAMETER   missing parameter
44913498266Sopenharmony_ci */
45013498266Sopenharmony_ciParameterError check_protocol(const char *str)
45113498266Sopenharmony_ci{
45213498266Sopenharmony_ci  if(!str)
45313498266Sopenharmony_ci    return PARAM_REQUIRES_PARAMETER;
45413498266Sopenharmony_ci
45513498266Sopenharmony_ci  if(proto_token(str))
45613498266Sopenharmony_ci    return PARAM_OK;
45713498266Sopenharmony_ci  return PARAM_LIBCURL_UNSUPPORTED_PROTOCOL;
45813498266Sopenharmony_ci}
45913498266Sopenharmony_ci
46013498266Sopenharmony_ci/**
46113498266Sopenharmony_ci * Parses the given string looking for an offset (which may be a
46213498266Sopenharmony_ci * larger-than-integer value). The offset CANNOT be negative!
46313498266Sopenharmony_ci *
46413498266Sopenharmony_ci * @param val  the offset to populate
46513498266Sopenharmony_ci * @param str  the buffer containing the offset
46613498266Sopenharmony_ci * @return PARAM_OK if successful, a parameter specific error enum if failure.
46713498266Sopenharmony_ci */
46813498266Sopenharmony_ciParameterError str2offset(curl_off_t *val, const char *str)
46913498266Sopenharmony_ci{
47013498266Sopenharmony_ci  char *endptr;
47113498266Sopenharmony_ci  if(str[0] == '-')
47213498266Sopenharmony_ci    /* offsets aren't negative, this indicates weird input */
47313498266Sopenharmony_ci    return PARAM_NEGATIVE_NUMERIC;
47413498266Sopenharmony_ci
47513498266Sopenharmony_ci#if(SIZEOF_CURL_OFF_T > SIZEOF_LONG)
47613498266Sopenharmony_ci  {
47713498266Sopenharmony_ci    CURLofft offt = curlx_strtoofft(str, &endptr, 10, val);
47813498266Sopenharmony_ci    if(CURL_OFFT_FLOW == offt)
47913498266Sopenharmony_ci      return PARAM_NUMBER_TOO_LARGE;
48013498266Sopenharmony_ci    else if(CURL_OFFT_INVAL == offt)
48113498266Sopenharmony_ci      return PARAM_BAD_NUMERIC;
48213498266Sopenharmony_ci  }
48313498266Sopenharmony_ci#else
48413498266Sopenharmony_ci  errno = 0;
48513498266Sopenharmony_ci  *val = strtol(str, &endptr, 0);
48613498266Sopenharmony_ci  if((*val == LONG_MIN || *val == LONG_MAX) && errno == ERANGE)
48713498266Sopenharmony_ci    return PARAM_NUMBER_TOO_LARGE;
48813498266Sopenharmony_ci#endif
48913498266Sopenharmony_ci  if((endptr != str) && (endptr == str + strlen(str)))
49013498266Sopenharmony_ci    return PARAM_OK;
49113498266Sopenharmony_ci
49213498266Sopenharmony_ci  return PARAM_BAD_NUMERIC;
49313498266Sopenharmony_ci}
49413498266Sopenharmony_ci
49513498266Sopenharmony_ci#define MAX_USERPWDLENGTH (100*1024)
49613498266Sopenharmony_cistatic CURLcode checkpasswd(const char *kind, /* for what purpose */
49713498266Sopenharmony_ci                            const size_t i,   /* operation index */
49813498266Sopenharmony_ci                            const bool last,  /* TRUE if last operation */
49913498266Sopenharmony_ci                            char **userpwd)   /* pointer to allocated string */
50013498266Sopenharmony_ci{
50113498266Sopenharmony_ci  char *psep;
50213498266Sopenharmony_ci  char *osep;
50313498266Sopenharmony_ci
50413498266Sopenharmony_ci  if(!*userpwd)
50513498266Sopenharmony_ci    return CURLE_OK;
50613498266Sopenharmony_ci
50713498266Sopenharmony_ci  /* Attempt to find the password separator */
50813498266Sopenharmony_ci  psep = strchr(*userpwd, ':');
50913498266Sopenharmony_ci
51013498266Sopenharmony_ci  /* Attempt to find the options separator */
51113498266Sopenharmony_ci  osep = strchr(*userpwd, ';');
51213498266Sopenharmony_ci
51313498266Sopenharmony_ci  if(!psep && **userpwd != ';') {
51413498266Sopenharmony_ci    /* no password present, prompt for one */
51513498266Sopenharmony_ci    char passwd[2048] = "";
51613498266Sopenharmony_ci    char prompt[256];
51713498266Sopenharmony_ci    struct curlx_dynbuf dyn;
51813498266Sopenharmony_ci
51913498266Sopenharmony_ci    curlx_dyn_init(&dyn, MAX_USERPWDLENGTH);
52013498266Sopenharmony_ci    if(osep)
52113498266Sopenharmony_ci      *osep = '\0';
52213498266Sopenharmony_ci
52313498266Sopenharmony_ci    /* build a nice-looking prompt */
52413498266Sopenharmony_ci    if(!i && last)
52513498266Sopenharmony_ci      curlx_msnprintf(prompt, sizeof(prompt),
52613498266Sopenharmony_ci                      "Enter %s password for user '%s':",
52713498266Sopenharmony_ci                      kind, *userpwd);
52813498266Sopenharmony_ci    else
52913498266Sopenharmony_ci      curlx_msnprintf(prompt, sizeof(prompt),
53013498266Sopenharmony_ci                      "Enter %s password for user '%s' on URL #%zu:",
53113498266Sopenharmony_ci                      kind, *userpwd, i + 1);
53213498266Sopenharmony_ci
53313498266Sopenharmony_ci    /* get password */
53413498266Sopenharmony_ci    getpass_r(prompt, passwd, sizeof(passwd));
53513498266Sopenharmony_ci    if(osep)
53613498266Sopenharmony_ci      *osep = ';';
53713498266Sopenharmony_ci
53813498266Sopenharmony_ci    if(curlx_dyn_addf(&dyn, "%s:%s", *userpwd, passwd))
53913498266Sopenharmony_ci      return CURLE_OUT_OF_MEMORY;
54013498266Sopenharmony_ci
54113498266Sopenharmony_ci    /* return the new string */
54213498266Sopenharmony_ci    free(*userpwd);
54313498266Sopenharmony_ci    *userpwd = curlx_dyn_ptr(&dyn);
54413498266Sopenharmony_ci  }
54513498266Sopenharmony_ci
54613498266Sopenharmony_ci  return CURLE_OK;
54713498266Sopenharmony_ci}
54813498266Sopenharmony_ci
54913498266Sopenharmony_ciParameterError add2list(struct curl_slist **list, const char *ptr)
55013498266Sopenharmony_ci{
55113498266Sopenharmony_ci  struct curl_slist *newlist = curl_slist_append(*list, ptr);
55213498266Sopenharmony_ci  if(newlist)
55313498266Sopenharmony_ci    *list = newlist;
55413498266Sopenharmony_ci  else
55513498266Sopenharmony_ci    return PARAM_NO_MEM;
55613498266Sopenharmony_ci
55713498266Sopenharmony_ci  return PARAM_OK;
55813498266Sopenharmony_ci}
55913498266Sopenharmony_ci
56013498266Sopenharmony_ciint ftpfilemethod(struct OperationConfig *config, const char *str)
56113498266Sopenharmony_ci{
56213498266Sopenharmony_ci  if(curl_strequal("singlecwd", str))
56313498266Sopenharmony_ci    return CURLFTPMETHOD_SINGLECWD;
56413498266Sopenharmony_ci  if(curl_strequal("nocwd", str))
56513498266Sopenharmony_ci    return CURLFTPMETHOD_NOCWD;
56613498266Sopenharmony_ci  if(curl_strequal("multicwd", str))
56713498266Sopenharmony_ci    return CURLFTPMETHOD_MULTICWD;
56813498266Sopenharmony_ci
56913498266Sopenharmony_ci  warnf(config->global, "unrecognized ftp file method '%s', using default",
57013498266Sopenharmony_ci        str);
57113498266Sopenharmony_ci
57213498266Sopenharmony_ci  return CURLFTPMETHOD_MULTICWD;
57313498266Sopenharmony_ci}
57413498266Sopenharmony_ci
57513498266Sopenharmony_ciint ftpcccmethod(struct OperationConfig *config, const char *str)
57613498266Sopenharmony_ci{
57713498266Sopenharmony_ci  if(curl_strequal("passive", str))
57813498266Sopenharmony_ci    return CURLFTPSSL_CCC_PASSIVE;
57913498266Sopenharmony_ci  if(curl_strequal("active", str))
58013498266Sopenharmony_ci    return CURLFTPSSL_CCC_ACTIVE;
58113498266Sopenharmony_ci
58213498266Sopenharmony_ci  warnf(config->global, "unrecognized ftp CCC method '%s', using default",
58313498266Sopenharmony_ci        str);
58413498266Sopenharmony_ci
58513498266Sopenharmony_ci  return CURLFTPSSL_CCC_PASSIVE;
58613498266Sopenharmony_ci}
58713498266Sopenharmony_ci
58813498266Sopenharmony_cilong delegation(struct OperationConfig *config, const char *str)
58913498266Sopenharmony_ci{
59013498266Sopenharmony_ci  if(curl_strequal("none", str))
59113498266Sopenharmony_ci    return CURLGSSAPI_DELEGATION_NONE;
59213498266Sopenharmony_ci  if(curl_strequal("policy", str))
59313498266Sopenharmony_ci    return CURLGSSAPI_DELEGATION_POLICY_FLAG;
59413498266Sopenharmony_ci  if(curl_strequal("always", str))
59513498266Sopenharmony_ci    return CURLGSSAPI_DELEGATION_FLAG;
59613498266Sopenharmony_ci
59713498266Sopenharmony_ci  warnf(config->global, "unrecognized delegation method '%s', using none",
59813498266Sopenharmony_ci        str);
59913498266Sopenharmony_ci
60013498266Sopenharmony_ci  return CURLGSSAPI_DELEGATION_NONE;
60113498266Sopenharmony_ci}
60213498266Sopenharmony_ci
60313498266Sopenharmony_ci/*
60413498266Sopenharmony_ci * my_useragent: returns allocated string with default user agent
60513498266Sopenharmony_ci */
60613498266Sopenharmony_cistatic char *my_useragent(void)
60713498266Sopenharmony_ci{
60813498266Sopenharmony_ci  return strdup(CURL_NAME "/" CURL_VERSION);
60913498266Sopenharmony_ci}
61013498266Sopenharmony_ci
61113498266Sopenharmony_ci#define isheadersep(x) ((((x)==':') || ((x)==';')))
61213498266Sopenharmony_ci
61313498266Sopenharmony_ci/*
61413498266Sopenharmony_ci * inlist() returns true if the given 'checkfor' header is present in the
61513498266Sopenharmony_ci * header list.
61613498266Sopenharmony_ci */
61713498266Sopenharmony_cistatic bool inlist(const struct curl_slist *head,
61813498266Sopenharmony_ci                   const char *checkfor)
61913498266Sopenharmony_ci{
62013498266Sopenharmony_ci  size_t thislen = strlen(checkfor);
62113498266Sopenharmony_ci  DEBUGASSERT(thislen);
62213498266Sopenharmony_ci  DEBUGASSERT(checkfor[thislen-1] != ':');
62313498266Sopenharmony_ci
62413498266Sopenharmony_ci  for(; head; head = head->next) {
62513498266Sopenharmony_ci    if(curl_strnequal(head->data, checkfor, thislen) &&
62613498266Sopenharmony_ci       isheadersep(head->data[thislen]) )
62713498266Sopenharmony_ci      return TRUE;
62813498266Sopenharmony_ci  }
62913498266Sopenharmony_ci
63013498266Sopenharmony_ci  return FALSE;
63113498266Sopenharmony_ci}
63213498266Sopenharmony_ci
63313498266Sopenharmony_ciCURLcode get_args(struct OperationConfig *config, const size_t i)
63413498266Sopenharmony_ci{
63513498266Sopenharmony_ci  CURLcode result = CURLE_OK;
63613498266Sopenharmony_ci  bool last = (config->next ? FALSE : TRUE);
63713498266Sopenharmony_ci
63813498266Sopenharmony_ci  if(config->jsoned) {
63913498266Sopenharmony_ci    ParameterError err = PARAM_OK;
64013498266Sopenharmony_ci    /* --json also implies json Content-Type: and Accept: headers - if
64113498266Sopenharmony_ci       they are not set with -H */
64213498266Sopenharmony_ci    if(!inlist(config->headers, "Content-Type"))
64313498266Sopenharmony_ci      err = add2list(&config->headers, "Content-Type: application/json");
64413498266Sopenharmony_ci    if(!err && !inlist(config->headers, "Accept"))
64513498266Sopenharmony_ci      err = add2list(&config->headers, "Accept: application/json");
64613498266Sopenharmony_ci    if(err)
64713498266Sopenharmony_ci      return CURLE_OUT_OF_MEMORY;
64813498266Sopenharmony_ci  }
64913498266Sopenharmony_ci
65013498266Sopenharmony_ci  /* Check we have a password for the given host user */
65113498266Sopenharmony_ci  if(config->userpwd && !config->oauth_bearer) {
65213498266Sopenharmony_ci    result = checkpasswd("host", i, last, &config->userpwd);
65313498266Sopenharmony_ci    if(result)
65413498266Sopenharmony_ci      return result;
65513498266Sopenharmony_ci  }
65613498266Sopenharmony_ci
65713498266Sopenharmony_ci  /* Check we have a password for the given proxy user */
65813498266Sopenharmony_ci  if(config->proxyuserpwd) {
65913498266Sopenharmony_ci    result = checkpasswd("proxy", i, last, &config->proxyuserpwd);
66013498266Sopenharmony_ci    if(result)
66113498266Sopenharmony_ci      return result;
66213498266Sopenharmony_ci  }
66313498266Sopenharmony_ci
66413498266Sopenharmony_ci  /* Check we have a user agent */
66513498266Sopenharmony_ci  if(!config->useragent) {
66613498266Sopenharmony_ci    config->useragent = my_useragent();
66713498266Sopenharmony_ci    if(!config->useragent) {
66813498266Sopenharmony_ci      errorf(config->global, "out of memory");
66913498266Sopenharmony_ci      result = CURLE_OUT_OF_MEMORY;
67013498266Sopenharmony_ci    }
67113498266Sopenharmony_ci  }
67213498266Sopenharmony_ci
67313498266Sopenharmony_ci  return result;
67413498266Sopenharmony_ci}
67513498266Sopenharmony_ci
67613498266Sopenharmony_ci/*
67713498266Sopenharmony_ci * Parse the string and modify ssl_version in the val argument. Return PARAM_OK
67813498266Sopenharmony_ci * on success, otherwise a parameter error enum. ONLY ACCEPTS POSITIVE NUMBERS!
67913498266Sopenharmony_ci *
68013498266Sopenharmony_ci * Since this function gets called with the 'nextarg' pointer from within the
68113498266Sopenharmony_ci * getparameter a lot, we must check it for NULL before accessing the str
68213498266Sopenharmony_ci * data.
68313498266Sopenharmony_ci */
68413498266Sopenharmony_ci
68513498266Sopenharmony_ciParameterError str2tls_max(long *val, const char *str)
68613498266Sopenharmony_ci{
68713498266Sopenharmony_ci   static struct s_tls_max {
68813498266Sopenharmony_ci    const char *tls_max_str;
68913498266Sopenharmony_ci    long tls_max;
69013498266Sopenharmony_ci  } const tls_max_array[] = {
69113498266Sopenharmony_ci    { "default", CURL_SSLVERSION_MAX_DEFAULT },
69213498266Sopenharmony_ci    { "1.0",     CURL_SSLVERSION_MAX_TLSv1_0 },
69313498266Sopenharmony_ci    { "1.1",     CURL_SSLVERSION_MAX_TLSv1_1 },
69413498266Sopenharmony_ci    { "1.2",     CURL_SSLVERSION_MAX_TLSv1_2 },
69513498266Sopenharmony_ci    { "1.3",     CURL_SSLVERSION_MAX_TLSv1_3 }
69613498266Sopenharmony_ci  };
69713498266Sopenharmony_ci  size_t i = 0;
69813498266Sopenharmony_ci  if(!str)
69913498266Sopenharmony_ci    return PARAM_REQUIRES_PARAMETER;
70013498266Sopenharmony_ci  for(i = 0; i < sizeof(tls_max_array)/sizeof(tls_max_array[0]); i++) {
70113498266Sopenharmony_ci    if(!strcmp(str, tls_max_array[i].tls_max_str)) {
70213498266Sopenharmony_ci      *val = tls_max_array[i].tls_max;
70313498266Sopenharmony_ci      return PARAM_OK;
70413498266Sopenharmony_ci    }
70513498266Sopenharmony_ci  }
70613498266Sopenharmony_ci  return PARAM_BAD_USE;
70713498266Sopenharmony_ci}
708