• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
new_getout(struct OperationConfig * config)40 struct 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 
file2string(char ** bufp,FILE * file)59 ParameterError 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 
file2memory(char ** bufp,size_t * size,FILE * file)107 ParameterError 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 
cleanarg(char * str)156 void 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 
str2num(long * val,const char * str)180 ParameterError 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 
str2unum(long * val,const char * str)206 ParameterError 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 
str2unummax(long * val,const char * str,long max)227 ParameterError 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 
str2double(double * val,const char * str,long max)251 static 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 
str2udouble(double * valp,const char * str,long max)284 ParameterError 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 
proto2num(struct OperationConfig * config,long * val,const char * str)308 long 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  */
check_protocol(const char * str)415 int 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  */
str2offset(curl_off_t * val,const char * str)436 ParameterError 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 
checkpasswd(const char * kind,const size_t i,const bool last,char ** userpwd)463 static 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 
add2list(struct curl_slist ** list,const char * ptr)524 ParameterError 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 
ftpfilemethod(struct OperationConfig * config,const char * str)535 int 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 
ftpcccmethod(struct OperationConfig * config,const char * str)550 int 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 
delegation(struct OperationConfig * config,char * str)563 long 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  */
my_useragent(void)581 static char *my_useragent(void)
582 {
583   return strdup(CURL_NAME "/" CURL_VERSION);
584 }
585 
get_args(struct OperationConfig * config,const size_t i)586 CURLcode 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 
str2tls_max(long * val,const char * str)626 ParameterError 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