• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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