xref: /curl/src/tool_paramhlp.c (revision 40c264db)
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 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.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  * SPDX-License-Identifier: curl
22  *
23  ***************************************************************************/
24 #include "tool_setup.h"
25 
26 #include "strcase.h"
27 
28 #include "curlx.h"
29 
30 #include "tool_cfgable.h"
31 #include "tool_getparam.h"
32 #include "tool_getpass.h"
33 #include "tool_msgs.h"
34 #include "tool_paramhlp.h"
35 #include "tool_libinfo.h"
36 #include "tool_util.h"
37 #include "tool_version.h"
38 #include "dynbuf.h"
39 
40 #include "memdebug.h" /* keep this as LAST include */
41 
new_getout(struct OperationConfig * config)42 struct getout *new_getout(struct OperationConfig *config)
43 {
44   struct getout *node = calloc(1, sizeof(struct getout));
45   struct getout *last = config->url_last;
46   if(node) {
47     static int outnum = 0;
48 
49     /* append this new node last in the list */
50     if(last)
51       last->next = node;
52     else
53       config->url_list = node; /* first node */
54 
55     /* move the last pointer */
56     config->url_last = node;
57 
58     node->flags = config->default_node_flags;
59     node->num = outnum++;
60   }
61   return node;
62 }
63 
64 #define ISCRLF(x) (((x) == '\r') || ((x) == '\n') || ((x) == '\0'))
65 
66 /* memcrlf() has two modes. Both operate on a given memory area with
67    a specified size.
68 
69    countcrlf FALSE - return number of bytes from the start that DO NOT include
70    any CR or LF or NULL
71 
72    countcrlf TRUE - return number of bytes from the start that are ONLY CR or
73    LF or NULL.
74 
75 */
memcrlf(char * orig,bool countcrlf,size_t max)76 static size_t memcrlf(char *orig,
77                       bool countcrlf, /* TRUE if we count CRLF, FALSE
78                                          if we count non-CRLF */
79                       size_t max)
80 {
81   char *ptr;
82   size_t total = max;
83   for(ptr = orig; max; max--, ptr++) {
84     bool crlf = ISCRLF(*ptr);
85     if(countcrlf ^ crlf)
86       return ptr - orig;
87   }
88   return total; /* no delimiter found */
89 }
90 
91 #define MAX_FILE2STRING MAX_FILE2MEMORY
92 
file2string(char ** bufp,FILE * file)93 ParameterError file2string(char **bufp, FILE *file)
94 {
95   struct curlx_dynbuf dyn;
96   curlx_dyn_init(&dyn, MAX_FILE2STRING);
97   if(file) {
98     do {
99       char buffer[4096];
100       char *ptr;
101       size_t nread = fread(buffer, 1, sizeof(buffer), file);
102       if(ferror(file)) {
103         curlx_dyn_free(&dyn);
104         *bufp = NULL;
105         return PARAM_READ_ERROR;
106       }
107       ptr = buffer;
108       while(nread) {
109         size_t nlen = memcrlf(ptr, FALSE, nread);
110         if(curlx_dyn_addn(&dyn, ptr, nlen))
111           return PARAM_NO_MEM;
112         nread -= nlen;
113 
114         if(nread) {
115           ptr += nlen;
116           nlen = memcrlf(ptr, TRUE, nread);
117           ptr += nlen;
118           nread -= nlen;
119         }
120       }
121     } while(!feof(file));
122   }
123   *bufp = curlx_dyn_ptr(&dyn);
124   return PARAM_OK;
125 }
126 
myfseek(void * stream,curl_off_t offset,int whence)127 static int myfseek(void *stream, curl_off_t offset, int whence)
128 {
129 #if defined(_WIN32) && defined(USE_WIN32_LARGE_FILES)
130   return _fseeki64(stream, (__int64)offset, whence);
131 #elif defined(HAVE_FSEEKO) && defined(HAVE_DECL_FSEEKO)
132   return fseeko(stream, (off_t)offset, whence);
133 #else
134   if(offset > LONG_MAX)
135     return -1;
136   return fseek(stream, (long)offset, whence);
137 #endif
138 }
139 
file2memory_range(char ** bufp,size_t * size,FILE * file,curl_off_t starto,curl_off_t endo)140 ParameterError file2memory_range(char **bufp, size_t *size, FILE *file,
141                                  curl_off_t starto, curl_off_t endo)
142 {
143   if(file) {
144     size_t nread;
145     struct curlx_dynbuf dyn;
146     curl_off_t offset = 0;
147     curl_off_t throwaway = 0;
148 
149     if(starto) {
150       if(file != stdin) {
151         if(myfseek(file, starto, SEEK_SET))
152           return PARAM_READ_ERROR;
153         offset = starto;
154       }
155       else
156         /* we can't seek stdin, read 'starto' bytes and throw them away */
157         throwaway = starto;
158     }
159 
160     /* The size needs to fit in an int later */
161     curlx_dyn_init(&dyn, MAX_FILE2MEMORY);
162     do {
163       char buffer[4096];
164       size_t n_add;
165       char *ptr_add;
166       nread = fread(buffer, 1, sizeof(buffer), file);
167       if(ferror(file)) {
168         curlx_dyn_free(&dyn);
169         *size = 0;
170         *bufp = NULL;
171         return PARAM_READ_ERROR;
172       }
173       n_add = nread;
174       ptr_add = buffer;
175       if(nread) {
176         if(throwaway) {
177           if(throwaway >= (curl_off_t)nread) {
178             throwaway -= nread;
179             offset += nread;
180             n_add = 0; /* nothing to add */
181           }
182           else {
183             /* append the trailing piece */
184             n_add = (size_t)(nread - throwaway);
185             ptr_add = &buffer[throwaway];
186             offset += throwaway;
187             throwaway = 0;
188           }
189         }
190         if(n_add) {
191           if((curl_off_t)(n_add + offset) > endo)
192             n_add = (size_t)(endo - offset + 1);
193 
194           if(curlx_dyn_addn(&dyn, ptr_add, n_add))
195             return PARAM_NO_MEM;
196 
197           offset += n_add;
198           if(offset > endo)
199             break;
200         }
201       }
202     } while(!feof(file));
203     *size = curlx_dyn_len(&dyn);
204     *bufp = curlx_dyn_ptr(&dyn);
205   }
206   else {
207     *size = 0;
208     *bufp = NULL;
209   }
210   return PARAM_OK;
211 }
212 
file2memory(char ** bufp,size_t * size,FILE * file)213 ParameterError file2memory(char **bufp, size_t *size, FILE *file)
214 {
215   return file2memory_range(bufp, size, file, 0, CURL_OFF_T_MAX);
216 }
217 
218 /*
219  * Parse the string and write the long in the given address. Return PARAM_OK
220  * on success, otherwise a parameter specific error enum.
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  */
getnum(long * val,const char * str,int base)226 static ParameterError getnum(long *val, const char *str, int base)
227 {
228   if(str) {
229     char *endptr = NULL;
230     long num;
231     if(!str[0])
232       return PARAM_BLANK_STRING;
233     errno = 0;
234     num = strtol(str, &endptr, base);
235     if(errno == ERANGE)
236       return PARAM_NUMBER_TOO_LARGE;
237     if((endptr != str) && (*endptr == '\0')) {
238       *val = num;
239       return PARAM_OK;  /* Ok */
240     }
241   }
242   return PARAM_BAD_NUMERIC; /* badness */
243 }
244 
str2num(long * val,const char * str)245 ParameterError str2num(long *val, const char *str)
246 {
247   return getnum(val, str, 10);
248 }
249 
oct2nummax(long * val,const char * str,long max)250 ParameterError oct2nummax(long *val, const char *str, long max)
251 {
252   ParameterError result = getnum(val, str, 8);
253   if(result != PARAM_OK)
254     return result;
255   else if(*val > max)
256     return PARAM_NUMBER_TOO_LARGE;
257   else if(*val < 0)
258     return PARAM_NEGATIVE_NUMERIC;
259 
260   return PARAM_OK;
261 }
262 
263 /*
264  * Parse the string and write the long in the given address. Return PARAM_OK
265  * on success, otherwise a parameter error enum. ONLY ACCEPTS POSITIVE NUMBERS!
266  *
267  * Since this function gets called with the 'nextarg' pointer from within the
268  * getparameter a lot, we must check it for NULL before accessing the str
269  * data.
270  */
271 
str2unum(long * val,const char * str)272 ParameterError str2unum(long *val, const char *str)
273 {
274   ParameterError result = getnum(val, str, 10);
275   if(result != PARAM_OK)
276     return result;
277   if(*val < 0)
278     return PARAM_NEGATIVE_NUMERIC;
279 
280   return PARAM_OK;
281 }
282 
283 /*
284  * Parse the string and write the long in the given address if it is below the
285  * maximum allowed value. Return PARAM_OK on success, otherwise a parameter
286  * error enum. ONLY ACCEPTS POSITIVE NUMBERS!
287  *
288  * Since this function gets called with the 'nextarg' pointer from within the
289  * getparameter a lot, we must check it for NULL before accessing the str
290  * data.
291  */
292 
str2unummax(long * val,const char * str,long max)293 ParameterError str2unummax(long *val, const char *str, long max)
294 {
295   ParameterError result = str2unum(val, str);
296   if(result != PARAM_OK)
297     return result;
298   if(*val > max)
299     return PARAM_NUMBER_TOO_LARGE;
300 
301   return PARAM_OK;
302 }
303 
304 
305 /*
306  * Parse the string and write the double in the given address. Return PARAM_OK
307  * on success, otherwise a parameter specific error enum.
308  *
309  * The 'max' argument is the maximum value allowed, as the numbers are often
310  * multiplied when later used.
311  *
312  * Since this function gets called with the 'nextarg' pointer from within the
313  * getparameter a lot, we must check it for NULL before accessing the str
314  * data.
315  */
316 
str2double(double * val,const char * str,double max)317 static ParameterError str2double(double *val, const char *str, double max)
318 {
319   if(str) {
320     char *endptr;
321     double num;
322     errno = 0;
323     num = strtod(str, &endptr);
324     if(errno == ERANGE)
325       return PARAM_NUMBER_TOO_LARGE;
326     if(num > max) {
327       /* too large */
328       return PARAM_NUMBER_TOO_LARGE;
329     }
330     if((endptr != str) && (endptr == str + strlen(str))) {
331       *val = num;
332       return PARAM_OK;  /* Ok */
333     }
334   }
335   return PARAM_BAD_NUMERIC; /* badness */
336 }
337 
338 /*
339  * Parse the string as seconds with decimals, and write the number of
340  * milliseconds that corresponds in the given address. Return PARAM_OK on
341  * success, otherwise a parameter error enum. ONLY ACCEPTS POSITIVE NUMBERS!
342  *
343  * The 'max' argument is the maximum value allowed, as the numbers are often
344  * multiplied when later used.
345  *
346  * Since this function gets called with the 'nextarg' pointer from within the
347  * getparameter a lot, we must check it for NULL before accessing the str
348  * data.
349  */
350 
secs2ms(long * valp,const char * str)351 ParameterError secs2ms(long *valp, const char *str)
352 {
353   double value;
354   ParameterError result = str2double(&value, str, (double)LONG_MAX/1000);
355   if(result != PARAM_OK)
356     return result;
357   if(value < 0)
358     return PARAM_NEGATIVE_NUMERIC;
359 
360   *valp = (long)(value*1000);
361   return PARAM_OK;
362 }
363 
364 /*
365  * Implement protocol sets in null-terminated array of protocol name pointers.
366  */
367 
368 /* Return index of prototype token in set, card(set) if not found.
369    Can be called with proto == NULL to get card(set). */
protoset_index(const char * const * protoset,const char * proto)370 static size_t protoset_index(const char * const *protoset, const char *proto)
371 {
372   const char * const *p = protoset;
373 
374   DEBUGASSERT(proto == proto_token(proto));     /* Ensure it is tokenized. */
375 
376   for(; *p; p++)
377     if(proto == *p)
378       break;
379   return p - protoset;
380 }
381 
382 /* Include protocol token in set. */
protoset_set(const char ** protoset,const char * proto)383 static void protoset_set(const char **protoset, const char *proto)
384 {
385   if(proto) {
386     size_t n = protoset_index(protoset, proto);
387 
388     if(!protoset[n]) {
389       DEBUGASSERT(n < proto_count);
390       protoset[n] = proto;
391       protoset[n + 1] = NULL;
392     }
393   }
394 }
395 
396 /* Exclude protocol token from set. */
protoset_clear(const char ** protoset,const char * proto)397 static void protoset_clear(const char **protoset, const char *proto)
398 {
399   if(proto) {
400     size_t n = protoset_index(protoset, proto);
401 
402     if(protoset[n]) {
403       size_t m = protoset_index(protoset, NULL) - 1;
404 
405       protoset[n] = protoset[m];
406       protoset[m] = NULL;
407     }
408   }
409 }
410 
411 /*
412  * Parse the string and provide an allocated libcurl compatible protocol
413  * string output. Return non-zero on failure, zero on success.
414  *
415  * The string is a list of protocols
416  *
417  * Since this function gets called with the 'nextarg' pointer from within the
418  * getparameter a lot, we must check it for NULL before accessing the str
419  * data.
420  */
421 
422 #define MAX_PROTOSTRING (64*11) /* Enough room for 64 10-chars proto names. */
423 
proto2num(struct OperationConfig * config,const char * const * val,char ** ostr,const char * str)424 ParameterError proto2num(struct OperationConfig *config,
425                          const char * const *val, char **ostr, const char *str)
426 {
427   char *buffer;
428   const char *sep = ",";
429   char *token;
430   const char **protoset;
431   struct curlx_dynbuf obuf;
432   size_t proto;
433   CURLcode result;
434 
435   curlx_dyn_init(&obuf, MAX_PROTOSTRING);
436 
437   if(!str)
438     return PARAM_OPTION_AMBIGUOUS;
439 
440   buffer = strdup(str); /* because strtok corrupts it */
441   if(!buffer)
442     return PARAM_NO_MEM;
443 
444   protoset = malloc((proto_count + 1) * sizeof(*protoset));
445   if(!protoset) {
446     free(buffer);
447     return PARAM_NO_MEM;
448   }
449 
450   /* Preset protocol set with default values. */
451   protoset[0] = NULL;
452   for(; *val; val++) {
453     const char *p = proto_token(*val);
454 
455     if(p)
456       protoset_set(protoset, p);
457   }
458 
459   /* Allow strtok() here since this is not used threaded */
460   /* !checksrc! disable BANNEDFUNC 2 */
461   for(token = strtok(buffer, sep);
462       token;
463       token = strtok(NULL, sep)) {
464     enum e_action { allow, deny, set } action = allow;
465 
466     /* Process token modifiers */
467     while(!ISALNUM(*token)) { /* may be NULL if token is all modifiers */
468       switch(*token++) {
469       case '=':
470         action = set;
471         break;
472       case '-':
473         action = deny;
474         break;
475       case '+':
476         action = allow;
477         break;
478       default: /* Includes case of terminating NULL */
479         free(buffer);
480         free((char *) protoset);
481         return PARAM_BAD_USE;
482       }
483     }
484 
485     if(curl_strequal(token, "all")) {
486       switch(action) {
487       case deny:
488         protoset[0] = NULL;
489         break;
490       case allow:
491       case set:
492         memcpy((char *) protoset,
493                built_in_protos, (proto_count + 1) * sizeof(*protoset));
494         break;
495       }
496     }
497     else {
498       const char *p = proto_token(token);
499 
500       if(p)
501         switch(action) {
502         case deny:
503           protoset_clear(protoset, p);
504           break;
505         case set:
506           protoset[0] = NULL;
507           FALLTHROUGH();
508         case allow:
509           protoset_set(protoset, p);
510           break;
511         }
512       else { /* unknown protocol */
513         /* If they have specified only this protocol, we say treat it as
514            if no protocols are allowed */
515         if(action == set)
516           protoset[0] = NULL;
517         warnf(config->global, "unrecognized protocol '%s'", token);
518       }
519     }
520   }
521   free(buffer);
522 
523   /* We need the protocols in alphabetic order for CI tests requirements. */
524   qsort((char *) protoset, protoset_index(protoset, NULL), sizeof(*protoset),
525         struplocompare4sort);
526 
527   result = curlx_dyn_addn(&obuf, "", 0);
528   for(proto = 0; protoset[proto] && !result; proto++)
529     result = curlx_dyn_addf(&obuf, "%s,", protoset[proto]);
530   free((char *) protoset);
531   curlx_dyn_setlen(&obuf, curlx_dyn_len(&obuf) - 1);
532   free(*ostr);
533   *ostr = curlx_dyn_ptr(&obuf);
534 
535   return *ostr ? PARAM_OK : PARAM_NO_MEM;
536 }
537 
538 /**
539  * Check if the given string is a protocol supported by libcurl
540  *
541  * @param str  the protocol name
542  * @return PARAM_OK  protocol supported
543  * @return PARAM_LIBCURL_UNSUPPORTED_PROTOCOL  protocol not supported
544  * @return PARAM_REQUIRES_PARAMETER   missing parameter
545  */
check_protocol(const char * str)546 ParameterError check_protocol(const char *str)
547 {
548   if(!str)
549     return PARAM_REQUIRES_PARAMETER;
550 
551   if(proto_token(str))
552     return PARAM_OK;
553   return PARAM_LIBCURL_UNSUPPORTED_PROTOCOL;
554 }
555 
556 /**
557  * Parses the given string looking for an offset (which may be a
558  * larger-than-integer value). The offset CANNOT be negative!
559  *
560  * @param val  the offset to populate
561  * @param str  the buffer containing the offset
562  * @return PARAM_OK if successful, a parameter specific error enum if failure.
563  */
str2offset(curl_off_t * val,const char * str)564 ParameterError str2offset(curl_off_t *val, const char *str)
565 {
566   char *endptr;
567   if(str[0] == '-')
568     /* offsets are not negative, this indicates weird input */
569     return PARAM_NEGATIVE_NUMERIC;
570 
571 #if(SIZEOF_CURL_OFF_T > SIZEOF_LONG)
572   {
573     CURLofft offt = curlx_strtoofft(str, &endptr, 10, val);
574     if(CURL_OFFT_FLOW == offt)
575       return PARAM_NUMBER_TOO_LARGE;
576     else if(CURL_OFFT_INVAL == offt)
577       return PARAM_BAD_NUMERIC;
578   }
579 #else
580   errno = 0;
581   *val = strtol(str, &endptr, 0);
582   if((*val == LONG_MIN || *val == LONG_MAX) && errno == ERANGE)
583     return PARAM_NUMBER_TOO_LARGE;
584 #endif
585   if((endptr != str) && (endptr == str + strlen(str)))
586     return PARAM_OK;
587 
588   return PARAM_BAD_NUMERIC;
589 }
590 
591 #define MAX_USERPWDLENGTH (100*1024)
checkpasswd(const char * kind,const size_t i,const bool last,char ** userpwd)592 static CURLcode checkpasswd(const char *kind, /* for what purpose */
593                             const size_t i,   /* operation index */
594                             const bool last,  /* TRUE if last operation */
595                             char **userpwd)   /* pointer to allocated string */
596 {
597   char *psep;
598   char *osep;
599 
600   if(!*userpwd)
601     return CURLE_OK;
602 
603   /* Attempt to find the password separator */
604   psep = strchr(*userpwd, ':');
605 
606   /* Attempt to find the options separator */
607   osep = strchr(*userpwd, ';');
608 
609   if(!psep && **userpwd != ';') {
610     /* no password present, prompt for one */
611     char passwd[2048] = "";
612     char prompt[256];
613     struct curlx_dynbuf dyn;
614 
615     curlx_dyn_init(&dyn, MAX_USERPWDLENGTH);
616     if(osep)
617       *osep = '\0';
618 
619     /* build a nice-looking prompt */
620     if(!i && last)
621       msnprintf(prompt, sizeof(prompt),
622                 "Enter %s password for user '%s':",
623                 kind, *userpwd);
624     else
625       msnprintf(prompt, sizeof(prompt),
626                 "Enter %s password for user '%s' on URL #%zu:",
627                 kind, *userpwd, i + 1);
628 
629     /* get password */
630     getpass_r(prompt, passwd, sizeof(passwd));
631     if(osep)
632       *osep = ';';
633 
634     if(curlx_dyn_addf(&dyn, "%s:%s", *userpwd, passwd))
635       return CURLE_OUT_OF_MEMORY;
636 
637     /* return the new string */
638     free(*userpwd);
639     *userpwd = curlx_dyn_ptr(&dyn);
640   }
641 
642   return CURLE_OK;
643 }
644 
add2list(struct curl_slist ** list,const char * ptr)645 ParameterError add2list(struct curl_slist **list, const char *ptr)
646 {
647   struct curl_slist *newlist = curl_slist_append(*list, ptr);
648   if(newlist)
649     *list = newlist;
650   else
651     return PARAM_NO_MEM;
652 
653   return PARAM_OK;
654 }
655 
ftpfilemethod(struct OperationConfig * config,const char * str)656 int ftpfilemethod(struct OperationConfig *config, const char *str)
657 {
658   if(curl_strequal("singlecwd", str))
659     return CURLFTPMETHOD_SINGLECWD;
660   if(curl_strequal("nocwd", str))
661     return CURLFTPMETHOD_NOCWD;
662   if(curl_strequal("multicwd", str))
663     return CURLFTPMETHOD_MULTICWD;
664 
665   warnf(config->global, "unrecognized ftp file method '%s', using default",
666         str);
667 
668   return CURLFTPMETHOD_MULTICWD;
669 }
670 
ftpcccmethod(struct OperationConfig * config,const char * str)671 int ftpcccmethod(struct OperationConfig *config, const char *str)
672 {
673   if(curl_strequal("passive", str))
674     return CURLFTPSSL_CCC_PASSIVE;
675   if(curl_strequal("active", str))
676     return CURLFTPSSL_CCC_ACTIVE;
677 
678   warnf(config->global, "unrecognized ftp CCC method '%s', using default",
679         str);
680 
681   return CURLFTPSSL_CCC_PASSIVE;
682 }
683 
delegation(struct OperationConfig * config,const char * str)684 long delegation(struct OperationConfig *config, const char *str)
685 {
686   if(curl_strequal("none", str))
687     return CURLGSSAPI_DELEGATION_NONE;
688   if(curl_strequal("policy", str))
689     return CURLGSSAPI_DELEGATION_POLICY_FLAG;
690   if(curl_strequal("always", str))
691     return CURLGSSAPI_DELEGATION_FLAG;
692 
693   warnf(config->global, "unrecognized delegation method '%s', using none",
694         str);
695 
696   return CURLGSSAPI_DELEGATION_NONE;
697 }
698 
699 /*
700  * my_useragent: returns allocated string with default user agent
701  */
my_useragent(void)702 static char *my_useragent(void)
703 {
704   return strdup(CURL_NAME "/" CURL_VERSION);
705 }
706 
707 #define isheadersep(x) ((((x)==':') || ((x)==';')))
708 
709 /*
710  * inlist() returns true if the given 'checkfor' header is present in the
711  * header list.
712  */
inlist(const struct curl_slist * head,const char * checkfor)713 static bool inlist(const struct curl_slist *head,
714                    const char *checkfor)
715 {
716   size_t thislen = strlen(checkfor);
717   DEBUGASSERT(thislen);
718   DEBUGASSERT(checkfor[thislen-1] != ':');
719 
720   for(; head; head = head->next) {
721     if(curl_strnequal(head->data, checkfor, thislen) &&
722        isheadersep(head->data[thislen]) )
723       return TRUE;
724   }
725 
726   return FALSE;
727 }
728 
get_args(struct OperationConfig * config,const size_t i)729 CURLcode get_args(struct OperationConfig *config, const size_t i)
730 {
731   CURLcode result = CURLE_OK;
732   bool last = (config->next ? FALSE : TRUE);
733 
734   if(config->jsoned) {
735     ParameterError err = PARAM_OK;
736     /* --json also implies json Content-Type: and Accept: headers - if
737        they are not set with -H */
738     if(!inlist(config->headers, "Content-Type"))
739       err = add2list(&config->headers, "Content-Type: application/json");
740     if(!err && !inlist(config->headers, "Accept"))
741       err = add2list(&config->headers, "Accept: application/json");
742     if(err)
743       return CURLE_OUT_OF_MEMORY;
744   }
745 
746   /* Check we have a password for the given host user */
747   if(config->userpwd && !config->oauth_bearer) {
748     result = checkpasswd("host", i, last, &config->userpwd);
749     if(result)
750       return result;
751   }
752 
753   /* Check we have a password for the given proxy user */
754   if(config->proxyuserpwd) {
755     result = checkpasswd("proxy", i, last, &config->proxyuserpwd);
756     if(result)
757       return result;
758   }
759 
760   /* Check we have a user agent */
761   if(!config->useragent) {
762     config->useragent = my_useragent();
763     if(!config->useragent) {
764       errorf(config->global, "out of memory");
765       result = CURLE_OUT_OF_MEMORY;
766     }
767   }
768 
769   return result;
770 }
771 
772 /*
773  * Parse the string and modify ssl_version in the val argument. Return PARAM_OK
774  * on success, otherwise a parameter error enum. ONLY ACCEPTS POSITIVE NUMBERS!
775  *
776  * Since this function gets called with the 'nextarg' pointer from within the
777  * getparameter a lot, we must check it for NULL before accessing the str
778  * data.
779  */
780 
str2tls_max(long * val,const char * str)781 ParameterError str2tls_max(long *val, const char *str)
782 {
783    static struct s_tls_max {
784     const char *tls_max_str;
785     long tls_max;
786   } const tls_max_array[] = {
787     { "default", CURL_SSLVERSION_MAX_DEFAULT },
788     { "1.0",     CURL_SSLVERSION_MAX_TLSv1_0 },
789     { "1.1",     CURL_SSLVERSION_MAX_TLSv1_1 },
790     { "1.2",     CURL_SSLVERSION_MAX_TLSv1_2 },
791     { "1.3",     CURL_SSLVERSION_MAX_TLSv1_3 }
792   };
793   size_t i = 0;
794   if(!str)
795     return PARAM_REQUIRES_PARAMETER;
796   for(i = 0; i < sizeof(tls_max_array)/sizeof(tls_max_array[0]); i++) {
797     if(!strcmp(str, tls_max_array[i].tls_max_str)) {
798       *val = tls_max_array[i].tls_max;
799       return PARAM_OK;
800     }
801   }
802   return PARAM_BAD_USE;
803 }
804