comparison mupdf-source/thirdparty/curl/src/tool_paramhlp.c @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
comparison
equal deleted inserted replaced
1:1d09e1dec1d9 2:b50eed0cc0ef
1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2019, 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 *ptr;
62 char *string = NULL;
63
64 if(file) {
65 char buffer[256];
66 size_t stringlen = 0;
67 while(fgets(buffer, sizeof(buffer), file)) {
68 size_t buflen;
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 nused = 0;
95
96 if(file) {
97 size_t nread;
98 size_t alloc = 512;
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 long in the given address if it is below the
202 * maximum allowed value. Return PARAM_OK on success, otherwise a parameter
203 * error enum. ONLY ACCEPTS POSITIVE NUMBERS!
204 *
205 * Since this function gets called with the 'nextarg' pointer from within the
206 * getparameter a lot, we must check it for NULL before accessing the str
207 * data.
208 */
209
210 ParameterError str2unummax(long *val, const char *str, long max)
211 {
212 ParameterError result = str2unum(val, str);
213 if(result != PARAM_OK)
214 return result;
215 if(*val > max)
216 return PARAM_NUMBER_TOO_LARGE;
217
218 return PARAM_OK;
219 }
220
221
222 /*
223 * Parse the string and write the double in the given address. Return PARAM_OK
224 * on success, otherwise a parameter specific error enum.
225 *
226 * The 'max' argument is the maximum value allowed, as the numbers are often
227 * multiplied when later used.
228 *
229 * Since this function gets called with the 'nextarg' pointer from within the
230 * getparameter a lot, we must check it for NULL before accessing the str
231 * data.
232 */
233
234 static ParameterError str2double(double *val, const char *str, long max)
235 {
236 if(str) {
237 char *endptr;
238 double num;
239 errno = 0;
240 num = strtod(str, &endptr);
241 if(errno == ERANGE)
242 return PARAM_NUMBER_TOO_LARGE;
243 if(num > max) {
244 /* too large */
245 return PARAM_NUMBER_TOO_LARGE;
246 }
247 if((endptr != str) && (endptr == str + strlen(str))) {
248 *val = num;
249 return PARAM_OK; /* Ok */
250 }
251 }
252 return PARAM_BAD_NUMERIC; /* badness */
253 }
254
255 /*
256 * Parse the string and write the double in the given address. Return PARAM_OK
257 * on success, otherwise a parameter error enum. ONLY ACCEPTS POSITIVE NUMBERS!
258 *
259 * The 'max' argument is the maximum value allowed, as the numbers are often
260 * multiplied when later used.
261 *
262 * Since this function gets called with the 'nextarg' pointer from within the
263 * getparameter a lot, we must check it for NULL before accessing the str
264 * data.
265 */
266
267 ParameterError str2udouble(double *valp, const char *str, long max)
268 {
269 double value;
270 ParameterError result = str2double(&value, str, max);
271 if(result != PARAM_OK)
272 return result;
273 if(value < 0)
274 return PARAM_NEGATIVE_NUMERIC;
275
276 *valp = value;
277 return PARAM_OK;
278 }
279
280 /*
281 * Parse the string and modify the long in the given address. Return
282 * non-zero on failure, zero on success.
283 *
284 * The string is a list of protocols
285 *
286 * Since this function gets called with the 'nextarg' pointer from within the
287 * getparameter a lot, we must check it for NULL before accessing the str
288 * data.
289 */
290
291 long proto2num(struct OperationConfig *config, long *val, const char *str)
292 {
293 char *buffer;
294 const char *sep = ",";
295 char *token;
296
297 static struct sprotos {
298 const char *name;
299 long bit;
300 } const protos[] = {
301 { "all", CURLPROTO_ALL },
302 { "http", CURLPROTO_HTTP },
303 { "https", CURLPROTO_HTTPS },
304 { "ftp", CURLPROTO_FTP },
305 { "ftps", CURLPROTO_FTPS },
306 { "scp", CURLPROTO_SCP },
307 { "sftp", CURLPROTO_SFTP },
308 { "telnet", CURLPROTO_TELNET },
309 { "ldap", CURLPROTO_LDAP },
310 { "ldaps", CURLPROTO_LDAPS },
311 { "dict", CURLPROTO_DICT },
312 { "file", CURLPROTO_FILE },
313 { "tftp", CURLPROTO_TFTP },
314 { "imap", CURLPROTO_IMAP },
315 { "imaps", CURLPROTO_IMAPS },
316 { "pop3", CURLPROTO_POP3 },
317 { "pop3s", CURLPROTO_POP3S },
318 { "smtp", CURLPROTO_SMTP },
319 { "smtps", CURLPROTO_SMTPS },
320 { "rtsp", CURLPROTO_RTSP },
321 { "gopher", CURLPROTO_GOPHER },
322 { "smb", CURLPROTO_SMB },
323 { "smbs", CURLPROTO_SMBS },
324 { NULL, 0 }
325 };
326
327 if(!str)
328 return 1;
329
330 buffer = strdup(str); /* because strtok corrupts it */
331 if(!buffer)
332 return 1;
333
334 /* Allow strtok() here since this isn't used threaded */
335 /* !checksrc! disable BANNEDFUNC 2 */
336 for(token = strtok(buffer, sep);
337 token;
338 token = strtok(NULL, sep)) {
339 enum e_action { allow, deny, set } action = allow;
340
341 struct sprotos const *pp;
342
343 /* Process token modifiers */
344 while(!ISALNUM(*token)) { /* may be NULL if token is all modifiers */
345 switch (*token++) {
346 case '=':
347 action = set;
348 break;
349 case '-':
350 action = deny;
351 break;
352 case '+':
353 action = allow;
354 break;
355 default: /* Includes case of terminating NULL */
356 Curl_safefree(buffer);
357 return 1;
358 }
359 }
360
361 for(pp = protos; pp->name; pp++) {
362 if(curl_strequal(token, pp->name)) {
363 switch(action) {
364 case deny:
365 *val &= ~(pp->bit);
366 break;
367 case allow:
368 *val |= pp->bit;
369 break;
370 case set:
371 *val = pp->bit;
372 break;
373 }
374 break;
375 }
376 }
377
378 if(!(pp->name)) { /* unknown protocol */
379 /* If they have specified only this protocol, we say treat it as
380 if no protocols are allowed */
381 if(action == set)
382 *val = 0;
383 warnf(config->global, "unrecognized protocol '%s'\n", token);
384 }
385 }
386 Curl_safefree(buffer);
387 return 0;
388 }
389
390 /**
391 * Check if the given string is a protocol supported by libcurl
392 *
393 * @param str the protocol name
394 * @return PARAM_OK protocol supported
395 * @return PARAM_LIBCURL_UNSUPPORTED_PROTOCOL protocol not supported
396 * @return PARAM_REQUIRES_PARAMETER missing parameter
397 */
398 int check_protocol(const char *str)
399 {
400 const char * const *pp;
401 const curl_version_info_data *curlinfo = curl_version_info(CURLVERSION_NOW);
402 if(!str)
403 return PARAM_REQUIRES_PARAMETER;
404 for(pp = curlinfo->protocols; *pp; pp++) {
405 if(curl_strequal(*pp, str))
406 return PARAM_OK;
407 }
408 return PARAM_LIBCURL_UNSUPPORTED_PROTOCOL;
409 }
410
411 /**
412 * Parses the given string looking for an offset (which may be a
413 * larger-than-integer value). The offset CANNOT be negative!
414 *
415 * @param val the offset to populate
416 * @param str the buffer containing the offset
417 * @return PARAM_OK if successful, a parameter specific error enum if failure.
418 */
419 ParameterError str2offset(curl_off_t *val, const char *str)
420 {
421 char *endptr;
422 if(str[0] == '-')
423 /* offsets aren't negative, this indicates weird input */
424 return PARAM_NEGATIVE_NUMERIC;
425
426 #if(SIZEOF_CURL_OFF_T > SIZEOF_LONG)
427 {
428 CURLofft offt = curlx_strtoofft(str, &endptr, 0, val);
429 if(CURL_OFFT_FLOW == offt)
430 return PARAM_NUMBER_TOO_LARGE;
431 else if(CURL_OFFT_INVAL == offt)
432 return PARAM_BAD_NUMERIC;
433 }
434 #else
435 errno = 0;
436 *val = strtol(str, &endptr, 0);
437 if((*val == LONG_MIN || *val == LONG_MAX) && errno == ERANGE)
438 return PARAM_NUMBER_TOO_LARGE;
439 #endif
440 if((endptr != str) && (endptr == str + strlen(str)))
441 return PARAM_OK;
442
443 return PARAM_BAD_NUMERIC;
444 }
445
446 static CURLcode checkpasswd(const char *kind, /* for what purpose */
447 const size_t i, /* operation index */
448 const bool last, /* TRUE if last operation */
449 char **userpwd) /* pointer to allocated string */
450 {
451 char *psep;
452 char *osep;
453
454 if(!*userpwd)
455 return CURLE_OK;
456
457 /* Attempt to find the password separator */
458 psep = strchr(*userpwd, ':');
459
460 /* Attempt to find the options separator */
461 osep = strchr(*userpwd, ';');
462
463 if(!psep && **userpwd != ';') {
464 /* no password present, prompt for one */
465 char passwd[256] = "";
466 char prompt[256];
467 size_t passwdlen;
468 size_t userlen = strlen(*userpwd);
469 char *passptr;
470
471 if(osep)
472 *osep = '\0';
473
474 /* build a nice-looking prompt */
475 if(!i && last)
476 curlx_msnprintf(prompt, sizeof(prompt),
477 "Enter %s password for user '%s':",
478 kind, *userpwd);
479 else
480 curlx_msnprintf(prompt, sizeof(prompt),
481 "Enter %s password for user '%s' on URL #%zu:",
482 kind, *userpwd, i + 1);
483
484 /* get password */
485 getpass_r(prompt, passwd, sizeof(passwd));
486 passwdlen = strlen(passwd);
487
488 if(osep)
489 *osep = ';';
490
491 /* extend the allocated memory area to fit the password too */
492 passptr = realloc(*userpwd,
493 passwdlen + 1 + /* an extra for the colon */
494 userlen + 1); /* an extra for the zero */
495 if(!passptr)
496 return CURLE_OUT_OF_MEMORY;
497
498 /* append the password separated with a colon */
499 passptr[userlen] = ':';
500 memcpy(&passptr[userlen + 1], passwd, passwdlen + 1);
501 *userpwd = passptr;
502 }
503
504 return CURLE_OK;
505 }
506
507 ParameterError add2list(struct curl_slist **list, const char *ptr)
508 {
509 struct curl_slist *newlist = curl_slist_append(*list, ptr);
510 if(newlist)
511 *list = newlist;
512 else
513 return PARAM_NO_MEM;
514
515 return PARAM_OK;
516 }
517
518 int ftpfilemethod(struct OperationConfig *config, const char *str)
519 {
520 if(curl_strequal("singlecwd", str))
521 return CURLFTPMETHOD_SINGLECWD;
522 if(curl_strequal("nocwd", str))
523 return CURLFTPMETHOD_NOCWD;
524 if(curl_strequal("multicwd", str))
525 return CURLFTPMETHOD_MULTICWD;
526
527 warnf(config->global, "unrecognized ftp file method '%s', using default\n",
528 str);
529
530 return CURLFTPMETHOD_MULTICWD;
531 }
532
533 int ftpcccmethod(struct OperationConfig *config, const char *str)
534 {
535 if(curl_strequal("passive", str))
536 return CURLFTPSSL_CCC_PASSIVE;
537 if(curl_strequal("active", str))
538 return CURLFTPSSL_CCC_ACTIVE;
539
540 warnf(config->global, "unrecognized ftp CCC method '%s', using default\n",
541 str);
542
543 return CURLFTPSSL_CCC_PASSIVE;
544 }
545
546 long delegation(struct OperationConfig *config, char *str)
547 {
548 if(curl_strequal("none", str))
549 return CURLGSSAPI_DELEGATION_NONE;
550 if(curl_strequal("policy", str))
551 return CURLGSSAPI_DELEGATION_POLICY_FLAG;
552 if(curl_strequal("always", str))
553 return CURLGSSAPI_DELEGATION_FLAG;
554
555 warnf(config->global, "unrecognized delegation method '%s', using none\n",
556 str);
557
558 return CURLGSSAPI_DELEGATION_NONE;
559 }
560
561 /*
562 * my_useragent: returns allocated string with default user agent
563 */
564 static char *my_useragent(void)
565 {
566 return strdup(CURL_NAME "/" CURL_VERSION);
567 }
568
569 CURLcode get_args(struct OperationConfig *config, const size_t i)
570 {
571 CURLcode result = CURLE_OK;
572 bool last = (config->next ? FALSE : TRUE);
573
574 /* Check we have a password for the given host user */
575 if(config->userpwd && !config->oauth_bearer) {
576 result = checkpasswd("host", i, last, &config->userpwd);
577 if(result)
578 return result;
579 }
580
581 /* Check we have a password for the given proxy user */
582 if(config->proxyuserpwd) {
583 result = checkpasswd("proxy", i, last, &config->proxyuserpwd);
584 if(result)
585 return result;
586 }
587
588 /* Check we have a user agent */
589 if(!config->useragent) {
590 config->useragent = my_useragent();
591 if(!config->useragent) {
592 helpf(config->global->errors, "out of memory\n");
593 result = CURLE_OUT_OF_MEMORY;
594 }
595 }
596
597 return result;
598 }
599
600 /*
601 * Parse the string and modify ssl_version in the val argument. Return PARAM_OK
602 * on success, otherwise a parameter error enum. ONLY ACCEPTS POSITIVE NUMBERS!
603 *
604 * Since this function gets called with the 'nextarg' pointer from within the
605 * getparameter a lot, we must check it for NULL before accessing the str
606 * data.
607 */
608
609 ParameterError str2tls_max(long *val, const char *str)
610 {
611 static struct s_tls_max {
612 const char *tls_max_str;
613 long tls_max;
614 } const tls_max_array[] = {
615 { "default", CURL_SSLVERSION_MAX_DEFAULT },
616 { "1.0", CURL_SSLVERSION_MAX_TLSv1_0 },
617 { "1.1", CURL_SSLVERSION_MAX_TLSv1_1 },
618 { "1.2", CURL_SSLVERSION_MAX_TLSv1_2 },
619 { "1.3", CURL_SSLVERSION_MAX_TLSv1_3 }
620 };
621 size_t i = 0;
622 if(!str)
623 return PARAM_REQUIRES_PARAMETER;
624 for(i = 0; i < sizeof(tls_max_array)/sizeof(tls_max_array[0]); i++) {
625 if(!strcmp(str, tls_max_array[i].tls_max_str)) {
626 *val = tls_max_array[i].tls_max;
627 return PARAM_OK;
628 }
629 }
630 return PARAM_BAD_USE;
631 }