tool_paramhlp.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614
  1. /***************************************************************************
  2. * _ _ ____ _
  3. * Project ___| | | | _ \| |
  4. * / __| | | | |_) | |
  5. * | (__| |_| | _ <| |___
  6. * \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) 1998 - 2021, 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. ***************************************************************************/
  22. #include "tool_setup.h"
  23. #include "strcase.h"
  24. #define ENABLE_CURLX_PRINTF
  25. /* use our own printf() functions */
  26. #include "curlx.h"
  27. #include "tool_cfgable.h"
  28. #include "tool_getparam.h"
  29. #include "tool_getpass.h"
  30. #include "tool_homedir.h"
  31. #include "tool_msgs.h"
  32. #include "tool_paramhlp.h"
  33. #include "tool_version.h"
  34. #include "dynbuf.h"
  35. #include "memdebug.h" /* keep this as LAST include */
  36. struct getout *new_getout(struct OperationConfig *config)
  37. {
  38. struct getout *node = calloc(1, sizeof(struct getout));
  39. struct getout *last = config->url_last;
  40. if(node) {
  41. static int outnum = 0;
  42. /* append this new node last in the list */
  43. if(last)
  44. last->next = node;
  45. else
  46. config->url_list = node; /* first node */
  47. /* move the last pointer */
  48. config->url_last = node;
  49. node->flags = config->default_node_flags;
  50. node->num = outnum++;
  51. }
  52. return node;
  53. }
  54. #define MAX_FILE2STRING (256*1024*1024) /* big enough ? */
  55. ParameterError file2string(char **bufp, FILE *file)
  56. {
  57. struct curlx_dynbuf dyn;
  58. curlx_dyn_init(&dyn, MAX_FILE2STRING);
  59. if(file) {
  60. char buffer[256];
  61. while(fgets(buffer, sizeof(buffer), file)) {
  62. char *ptr = strchr(buffer, '\r');
  63. if(ptr)
  64. *ptr = '\0';
  65. ptr = strchr(buffer, '\n');
  66. if(ptr)
  67. *ptr = '\0';
  68. if(curlx_dyn_add(&dyn, buffer))
  69. return PARAM_NO_MEM;
  70. }
  71. }
  72. *bufp = curlx_dyn_ptr(&dyn);
  73. return PARAM_OK;
  74. }
  75. #define MAX_FILE2MEMORY (1024*1024*1024) /* big enough ? */
  76. ParameterError file2memory(char **bufp, size_t *size, FILE *file)
  77. {
  78. if(file) {
  79. size_t nread;
  80. struct curlx_dynbuf dyn;
  81. curlx_dyn_init(&dyn, MAX_FILE2MEMORY);
  82. do {
  83. char buffer[4096];
  84. nread = fread(buffer, 1, sizeof(buffer), file);
  85. if(nread)
  86. if(curlx_dyn_addn(&dyn, buffer, nread))
  87. return PARAM_NO_MEM;
  88. } while(nread);
  89. *size = curlx_dyn_len(&dyn);
  90. *bufp = curlx_dyn_ptr(&dyn);
  91. }
  92. else {
  93. *size = 0;
  94. *bufp = NULL;
  95. }
  96. return PARAM_OK;
  97. }
  98. void cleanarg(char *str)
  99. {
  100. #ifdef HAVE_WRITABLE_ARGV
  101. /* now that GetStr has copied the contents of nextarg, wipe the next
  102. * argument out so that the username:password isn't displayed in the
  103. * system process list */
  104. if(str) {
  105. size_t len = strlen(str);
  106. memset(str, ' ', len);
  107. }
  108. #else
  109. (void)str;
  110. #endif
  111. }
  112. /*
  113. * Parse the string and write the long in the given address. Return PARAM_OK
  114. * on success, otherwise a parameter specific error enum.
  115. *
  116. * Since this function gets called with the 'nextarg' pointer from within the
  117. * getparameter a lot, we must check it for NULL before accessing the str
  118. * data.
  119. */
  120. static ParameterError getnum(long *val, const char *str, int base)
  121. {
  122. if(str) {
  123. char *endptr = NULL;
  124. long num;
  125. errno = 0;
  126. num = strtol(str, &endptr, base);
  127. if(errno == ERANGE)
  128. return PARAM_NUMBER_TOO_LARGE;
  129. if((endptr != str) && (endptr == str + strlen(str))) {
  130. *val = num;
  131. return PARAM_OK; /* Ok */
  132. }
  133. }
  134. return PARAM_BAD_NUMERIC; /* badness */
  135. }
  136. ParameterError str2num(long *val, const char *str)
  137. {
  138. return getnum(val, str, 10);
  139. }
  140. ParameterError oct2nummax(long *val, const char *str, long max)
  141. {
  142. ParameterError result = getnum(val, str, 8);
  143. if(result != PARAM_OK)
  144. return result;
  145. else if(*val > max)
  146. return PARAM_NUMBER_TOO_LARGE;
  147. else if(*val < 0)
  148. return PARAM_NEGATIVE_NUMERIC;
  149. return PARAM_OK;
  150. }
  151. /*
  152. * Parse the string and write the long in the given address. Return PARAM_OK
  153. * on success, otherwise a parameter error enum. ONLY ACCEPTS POSITIVE NUMBERS!
  154. *
  155. * Since this function gets called with the 'nextarg' pointer from within the
  156. * getparameter a lot, we must check it for NULL before accessing the str
  157. * data.
  158. */
  159. ParameterError str2unum(long *val, const char *str)
  160. {
  161. ParameterError result = getnum(val, str, 10);
  162. if(result != PARAM_OK)
  163. return result;
  164. if(*val < 0)
  165. return PARAM_NEGATIVE_NUMERIC;
  166. return PARAM_OK;
  167. }
  168. /*
  169. * Parse the string and write the long in the given address if it is below the
  170. * maximum allowed value. Return PARAM_OK on success, otherwise a parameter
  171. * error enum. ONLY ACCEPTS POSITIVE NUMBERS!
  172. *
  173. * Since this function gets called with the 'nextarg' pointer from within the
  174. * getparameter a lot, we must check it for NULL before accessing the str
  175. * data.
  176. */
  177. ParameterError str2unummax(long *val, const char *str, long max)
  178. {
  179. ParameterError result = str2unum(val, str);
  180. if(result != PARAM_OK)
  181. return result;
  182. if(*val > max)
  183. return PARAM_NUMBER_TOO_LARGE;
  184. return PARAM_OK;
  185. }
  186. /*
  187. * Parse the string and write the double in the given address. Return PARAM_OK
  188. * on success, otherwise a parameter specific error enum.
  189. *
  190. * The 'max' argument is the maximum value allowed, as the numbers are often
  191. * multiplied when later used.
  192. *
  193. * Since this function gets called with the 'nextarg' pointer from within the
  194. * getparameter a lot, we must check it for NULL before accessing the str
  195. * data.
  196. */
  197. static ParameterError str2double(double *val, const char *str, long max)
  198. {
  199. if(str) {
  200. char *endptr;
  201. double num;
  202. errno = 0;
  203. num = strtod(str, &endptr);
  204. if(errno == ERANGE)
  205. return PARAM_NUMBER_TOO_LARGE;
  206. if(num > max) {
  207. /* too large */
  208. return PARAM_NUMBER_TOO_LARGE;
  209. }
  210. if((endptr != str) && (endptr == str + strlen(str))) {
  211. *val = num;
  212. return PARAM_OK; /* Ok */
  213. }
  214. }
  215. return PARAM_BAD_NUMERIC; /* badness */
  216. }
  217. /*
  218. * Parse the string and write the double in the given address. Return PARAM_OK
  219. * on success, otherwise a parameter error enum. ONLY ACCEPTS POSITIVE NUMBERS!
  220. *
  221. * The 'max' argument is the maximum value allowed, as the numbers are often
  222. * multiplied when later used.
  223. *
  224. * Since this function gets called with the 'nextarg' pointer from within the
  225. * getparameter a lot, we must check it for NULL before accessing the str
  226. * data.
  227. */
  228. ParameterError str2udouble(double *valp, const char *str, long max)
  229. {
  230. double value;
  231. ParameterError result = str2double(&value, str, max);
  232. if(result != PARAM_OK)
  233. return result;
  234. if(value < 0)
  235. return PARAM_NEGATIVE_NUMERIC;
  236. *valp = value;
  237. return PARAM_OK;
  238. }
  239. /*
  240. * Parse the string and modify the long in the given address. Return
  241. * non-zero on failure, zero on success.
  242. *
  243. * The string is a list of protocols
  244. *
  245. * Since this function gets called with the 'nextarg' pointer from within the
  246. * getparameter a lot, we must check it for NULL before accessing the str
  247. * data.
  248. */
  249. long proto2num(struct OperationConfig *config, long *val, const char *str)
  250. {
  251. char *buffer;
  252. const char *sep = ",";
  253. char *token;
  254. static struct sprotos {
  255. const char *name;
  256. long bit;
  257. } const protos[] = {
  258. { "all", CURLPROTO_ALL },
  259. { "http", CURLPROTO_HTTP },
  260. { "https", CURLPROTO_HTTPS },
  261. { "ftp", CURLPROTO_FTP },
  262. { "ftps", CURLPROTO_FTPS },
  263. { "scp", CURLPROTO_SCP },
  264. { "sftp", CURLPROTO_SFTP },
  265. { "telnet", CURLPROTO_TELNET },
  266. { "ldap", CURLPROTO_LDAP },
  267. { "ldaps", CURLPROTO_LDAPS },
  268. { "dict", CURLPROTO_DICT },
  269. { "file", CURLPROTO_FILE },
  270. { "tftp", CURLPROTO_TFTP },
  271. { "imap", CURLPROTO_IMAP },
  272. { "imaps", CURLPROTO_IMAPS },
  273. { "pop3", CURLPROTO_POP3 },
  274. { "pop3s", CURLPROTO_POP3S },
  275. { "smtp", CURLPROTO_SMTP },
  276. { "smtps", CURLPROTO_SMTPS },
  277. { "rtsp", CURLPROTO_RTSP },
  278. { "gopher", CURLPROTO_GOPHER },
  279. { "smb", CURLPROTO_SMB },
  280. { "smbs", CURLPROTO_SMBS },
  281. { NULL, 0 }
  282. };
  283. if(!str)
  284. return 1;
  285. buffer = strdup(str); /* because strtok corrupts it */
  286. if(!buffer)
  287. return 1;
  288. /* Allow strtok() here since this isn't used threaded */
  289. /* !checksrc! disable BANNEDFUNC 2 */
  290. for(token = strtok(buffer, sep);
  291. token;
  292. token = strtok(NULL, sep)) {
  293. enum e_action { allow, deny, set } action = allow;
  294. struct sprotos const *pp;
  295. /* Process token modifiers */
  296. while(!ISALNUM(*token)) { /* may be NULL if token is all modifiers */
  297. switch (*token++) {
  298. case '=':
  299. action = set;
  300. break;
  301. case '-':
  302. action = deny;
  303. break;
  304. case '+':
  305. action = allow;
  306. break;
  307. default: /* Includes case of terminating NULL */
  308. Curl_safefree(buffer);
  309. return 1;
  310. }
  311. }
  312. for(pp = protos; pp->name; pp++) {
  313. if(curl_strequal(token, pp->name)) {
  314. switch(action) {
  315. case deny:
  316. *val &= ~(pp->bit);
  317. break;
  318. case allow:
  319. *val |= pp->bit;
  320. break;
  321. case set:
  322. *val = pp->bit;
  323. break;
  324. }
  325. break;
  326. }
  327. }
  328. if(!(pp->name)) { /* unknown protocol */
  329. /* If they have specified only this protocol, we say treat it as
  330. if no protocols are allowed */
  331. if(action == set)
  332. *val = 0;
  333. warnf(config->global, "unrecognized protocol '%s'\n", token);
  334. }
  335. }
  336. Curl_safefree(buffer);
  337. return 0;
  338. }
  339. /**
  340. * Check if the given string is a protocol supported by libcurl
  341. *
  342. * @param str the protocol name
  343. * @return PARAM_OK protocol supported
  344. * @return PARAM_LIBCURL_UNSUPPORTED_PROTOCOL protocol not supported
  345. * @return PARAM_REQUIRES_PARAMETER missing parameter
  346. */
  347. int check_protocol(const char *str)
  348. {
  349. const char * const *pp;
  350. const curl_version_info_data *curlinfo = curl_version_info(CURLVERSION_NOW);
  351. if(!str)
  352. return PARAM_REQUIRES_PARAMETER;
  353. for(pp = curlinfo->protocols; *pp; pp++) {
  354. if(curl_strequal(*pp, str))
  355. return PARAM_OK;
  356. }
  357. return PARAM_LIBCURL_UNSUPPORTED_PROTOCOL;
  358. }
  359. /**
  360. * Parses the given string looking for an offset (which may be a
  361. * larger-than-integer value). The offset CANNOT be negative!
  362. *
  363. * @param val the offset to populate
  364. * @param str the buffer containing the offset
  365. * @return PARAM_OK if successful, a parameter specific error enum if failure.
  366. */
  367. ParameterError str2offset(curl_off_t *val, const char *str)
  368. {
  369. char *endptr;
  370. if(str[0] == '-')
  371. /* offsets aren't negative, this indicates weird input */
  372. return PARAM_NEGATIVE_NUMERIC;
  373. #if(SIZEOF_CURL_OFF_T > SIZEOF_LONG)
  374. {
  375. CURLofft offt = curlx_strtoofft(str, &endptr, 0, val);
  376. if(CURL_OFFT_FLOW == offt)
  377. return PARAM_NUMBER_TOO_LARGE;
  378. else if(CURL_OFFT_INVAL == offt)
  379. return PARAM_BAD_NUMERIC;
  380. }
  381. #else
  382. errno = 0;
  383. *val = strtol(str, &endptr, 0);
  384. if((*val == LONG_MIN || *val == LONG_MAX) && errno == ERANGE)
  385. return PARAM_NUMBER_TOO_LARGE;
  386. #endif
  387. if((endptr != str) && (endptr == str + strlen(str)))
  388. return PARAM_OK;
  389. return PARAM_BAD_NUMERIC;
  390. }
  391. #define MAX_USERPWDLENGTH (100*1024)
  392. static CURLcode checkpasswd(const char *kind, /* for what purpose */
  393. const size_t i, /* operation index */
  394. const bool last, /* TRUE if last operation */
  395. char **userpwd) /* pointer to allocated string */
  396. {
  397. char *psep;
  398. char *osep;
  399. if(!*userpwd)
  400. return CURLE_OK;
  401. /* Attempt to find the password separator */
  402. psep = strchr(*userpwd, ':');
  403. /* Attempt to find the options separator */
  404. osep = strchr(*userpwd, ';');
  405. if(!psep && **userpwd != ';') {
  406. /* no password present, prompt for one */
  407. char passwd[2048] = "";
  408. char prompt[256];
  409. struct curlx_dynbuf dyn;
  410. curlx_dyn_init(&dyn, MAX_USERPWDLENGTH);
  411. if(osep)
  412. *osep = '\0';
  413. /* build a nice-looking prompt */
  414. if(!i && last)
  415. curlx_msnprintf(prompt, sizeof(prompt),
  416. "Enter %s password for user '%s':",
  417. kind, *userpwd);
  418. else
  419. curlx_msnprintf(prompt, sizeof(prompt),
  420. "Enter %s password for user '%s' on URL #%zu:",
  421. kind, *userpwd, i + 1);
  422. /* get password */
  423. getpass_r(prompt, passwd, sizeof(passwd));
  424. if(osep)
  425. *osep = ';';
  426. if(curlx_dyn_addf(&dyn, "%s:%s", *userpwd, passwd))
  427. return CURLE_OUT_OF_MEMORY;
  428. /* return the new string */
  429. free(*userpwd);
  430. *userpwd = curlx_dyn_ptr(&dyn);
  431. }
  432. return CURLE_OK;
  433. }
  434. ParameterError add2list(struct curl_slist **list, const char *ptr)
  435. {
  436. struct curl_slist *newlist = curl_slist_append(*list, ptr);
  437. if(newlist)
  438. *list = newlist;
  439. else
  440. return PARAM_NO_MEM;
  441. return PARAM_OK;
  442. }
  443. int ftpfilemethod(struct OperationConfig *config, const char *str)
  444. {
  445. if(curl_strequal("singlecwd", str))
  446. return CURLFTPMETHOD_SINGLECWD;
  447. if(curl_strequal("nocwd", str))
  448. return CURLFTPMETHOD_NOCWD;
  449. if(curl_strequal("multicwd", str))
  450. return CURLFTPMETHOD_MULTICWD;
  451. warnf(config->global, "unrecognized ftp file method '%s', using default\n",
  452. str);
  453. return CURLFTPMETHOD_MULTICWD;
  454. }
  455. int ftpcccmethod(struct OperationConfig *config, const char *str)
  456. {
  457. if(curl_strequal("passive", str))
  458. return CURLFTPSSL_CCC_PASSIVE;
  459. if(curl_strequal("active", str))
  460. return CURLFTPSSL_CCC_ACTIVE;
  461. warnf(config->global, "unrecognized ftp CCC method '%s', using default\n",
  462. str);
  463. return CURLFTPSSL_CCC_PASSIVE;
  464. }
  465. long delegation(struct OperationConfig *config, const char *str)
  466. {
  467. if(curl_strequal("none", str))
  468. return CURLGSSAPI_DELEGATION_NONE;
  469. if(curl_strequal("policy", str))
  470. return CURLGSSAPI_DELEGATION_POLICY_FLAG;
  471. if(curl_strequal("always", str))
  472. return CURLGSSAPI_DELEGATION_FLAG;
  473. warnf(config->global, "unrecognized delegation method '%s', using none\n",
  474. str);
  475. return CURLGSSAPI_DELEGATION_NONE;
  476. }
  477. /*
  478. * my_useragent: returns allocated string with default user agent
  479. */
  480. static char *my_useragent(void)
  481. {
  482. return strdup(CURL_NAME "/" CURL_VERSION);
  483. }
  484. CURLcode get_args(struct OperationConfig *config, const size_t i)
  485. {
  486. CURLcode result = CURLE_OK;
  487. bool last = (config->next ? FALSE : TRUE);
  488. /* Check we have a password for the given host user */
  489. if(config->userpwd && !config->oauth_bearer) {
  490. result = checkpasswd("host", i, last, &config->userpwd);
  491. if(result)
  492. return result;
  493. }
  494. /* Check we have a password for the given proxy user */
  495. if(config->proxyuserpwd) {
  496. result = checkpasswd("proxy", i, last, &config->proxyuserpwd);
  497. if(result)
  498. return result;
  499. }
  500. /* Check we have a user agent */
  501. if(!config->useragent) {
  502. config->useragent = my_useragent();
  503. if(!config->useragent) {
  504. errorf(config->global, "out of memory\n");
  505. result = CURLE_OUT_OF_MEMORY;
  506. }
  507. }
  508. return result;
  509. }
  510. /*
  511. * Parse the string and modify ssl_version in the val argument. Return PARAM_OK
  512. * on success, otherwise a parameter error enum. ONLY ACCEPTS POSITIVE NUMBERS!
  513. *
  514. * Since this function gets called with the 'nextarg' pointer from within the
  515. * getparameter a lot, we must check it for NULL before accessing the str
  516. * data.
  517. */
  518. ParameterError str2tls_max(long *val, const char *str)
  519. {
  520. static struct s_tls_max {
  521. const char *tls_max_str;
  522. long tls_max;
  523. } const tls_max_array[] = {
  524. { "default", CURL_SSLVERSION_MAX_DEFAULT },
  525. { "1.0", CURL_SSLVERSION_MAX_TLSv1_0 },
  526. { "1.1", CURL_SSLVERSION_MAX_TLSv1_1 },
  527. { "1.2", CURL_SSLVERSION_MAX_TLSv1_2 },
  528. { "1.3", CURL_SSLVERSION_MAX_TLSv1_3 }
  529. };
  530. size_t i = 0;
  531. if(!str)
  532. return PARAM_REQUIRES_PARAMETER;
  533. for(i = 0; i < sizeof(tls_max_array)/sizeof(tls_max_array[0]); i++) {
  534. if(!strcmp(str, tls_max_array[i].tls_max_str)) {
  535. *val = tls_max_array[i].tls_max;
  536. return PARAM_OK;
  537. }
  538. }
  539. return PARAM_BAD_USE;
  540. }