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