tool_paramhlp.c 20 KB

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