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