Home | History | Annotate | Download | only in src
      1 /***************************************************************************
      2  *                                  _   _ ____  _
      3  *  Project                     ___| | | |  _ \| |
      4  *                             / __| | | | |_) | |
      5  *                            | (__| |_| |  _ <| |___
      6  *                             \___|\___/|_| \_\_____|
      7  *
      8  * Copyright (C) 1998 - 2016, 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       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 
     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 
    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 
    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 
    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 
    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 
    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 
    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  */
    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  */
    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 
    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 
    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 
    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 
    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 
    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  */
    513 static char *my_useragent(void)
    514 {
    515   return strdup(CURL_NAME "/" CURL_VERSION);
    516 }
    517 
    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