tool_paramhlp.c 17 KB

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