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