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