Home | History | Annotate | Download | only in src
      1 /***************************************************************************
      2  *                                  _   _ ____  _
      3  *  Project                     ___| | | |  _ \| |
      4  *                             / __| | | | |_) | |
      5  *                            | (__| |_| |  _ <| |___
      6  *                             \___|\___/|_| \_\_____|
      7  *
      8  * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel (at) 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 }
    611