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