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