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