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