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