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