~ubuntu-branches/ubuntu/lucid/curl/lucid-security

« back to all changes in this revision

Viewing changes to src/main.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2005-12-12 15:04:52 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20051212150452-2ymlra67b2p7kjyy
Tags: 7.15.1-1ubuntu1
Resynchronise with Debian to get URL parser overflow fix from 7.15.1
(CVE-2005-4077).

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19
19
 * KIND, either express or implied.
20
20
 *
21
 
 * $Id: main.c,v 1.324 2005/05/12 07:28:03 bagder Exp $
 
21
 * $Id: main.c,v 1.341 2005/12/05 14:10:48 bagder Exp $
22
22
 ***************************************************************************/
23
23
 
24
24
#include "setup.h"
243
243
#define ftruncate(fd,where) ftruncate64(fd,where)
244
244
#endif
245
245
 
 
246
typedef enum {
 
247
    TRACE_BIN,   /* tcpdump inspired look */
 
248
    TRACE_ASCII, /* like *BIN but without the hex output */
 
249
    TRACE_PLAIN  /* -v/--verbose type */
 
250
} trace;
 
251
 
 
252
struct Configurable {
 
253
  bool remote_time;
 
254
  char *random_file;
 
255
  char *egd_file;
 
256
  char *useragent;
 
257
  char *cookie;     /* single line with specified cookies */
 
258
  char *cookiejar;  /* write to this file */
 
259
  char *cookiefile; /* read from this file */
 
260
  bool cookiesession; /* new session? */
 
261
  bool encoding;    /* Accept-Encoding please */
 
262
  long authtype;    /* auth bitmask */
 
263
  bool use_resume;
 
264
  bool resume_from_current;
 
265
  bool disable_epsv;
 
266
  bool disable_eprt;
 
267
  curl_off_t resume_from;
 
268
  char *postfields;
 
269
  long postfieldsize;
 
270
  char *referer;
 
271
  long timeout;
 
272
  long connecttimeout;
 
273
  long maxredirs;
 
274
  curl_off_t max_filesize;
 
275
  char *headerfile;
 
276
  char *ftpport;
 
277
  char *iface;
 
278
  unsigned short porttouse;
 
279
  char *range;
 
280
  long low_speed_limit;
 
281
  long low_speed_time;
 
282
  bool showerror;
 
283
  char *userpwd;
 
284
  char *proxyuserpwd;
 
285
  char *proxy;
 
286
  bool proxytunnel;
 
287
  long conf;
 
288
  struct getout *url_list; /* point to the first node */
 
289
  struct getout *url_last; /* point to the last/current node */
 
290
  struct getout *url_get;  /* point to the node to fill in URL */
 
291
  struct getout *url_out;  /* point to the node to fill in outfile */
 
292
  char *cipher_list;
 
293
  char *cert;
 
294
  char *cert_type;
 
295
  char *cacert;
 
296
  char *capath;
 
297
  char *key;
 
298
  char *key_type;
 
299
  char *key_passwd;
 
300
  char *engine;
 
301
  bool list_engines;
 
302
  bool crlf;
 
303
  char *customrequest;
 
304
  char *krb4level;
 
305
  char *trace_dump; /* file to dump the network trace to, or NULL */
 
306
  FILE *trace_stream;
 
307
  bool trace_fopened;
 
308
  trace tracetype;
 
309
  bool tracetime; /* include timestamp? */
 
310
  long httpversion;
 
311
  bool progressmode;
 
312
  bool nobuffer;
 
313
  bool globoff;
 
314
  bool use_httpget;
 
315
  bool insecure_ok; /* set TRUE to allow insecure SSL connects */
 
316
  bool create_dirs;
 
317
  bool ftp_create_dirs;
 
318
  bool ftp_skip_ip;
 
319
  bool proxyntlm;
 
320
  bool proxydigest;
 
321
  bool proxybasic;
 
322
  bool proxyanyauth;
 
323
  char *writeout; /* %-styled format string to output */
 
324
  bool writeenv; /* write results to environment, if available */
 
325
  FILE *errors; /* if stderr redirect is requested */
 
326
  bool errors_fopened;
 
327
  struct curl_slist *quote;
 
328
  struct curl_slist *postquote;
 
329
  struct curl_slist *prequote;
 
330
  long ssl_version;
 
331
  long ip_version;
 
332
  curl_TimeCond timecond;
 
333
  time_t condtime;
 
334
  struct curl_slist *headers;
 
335
  struct curl_httppost *httppost;
 
336
  struct curl_httppost *last_post;
 
337
  struct curl_slist *telnet_options;
 
338
  HttpReq httpreq;
 
339
 
 
340
  /* for bandwidth limiting features: */
 
341
  curl_off_t sendpersecond; /* send to peer */
 
342
  curl_off_t recvpersecond; /* receive from peer */
 
343
  struct timeval lastsendtime;
 
344
  size_t lastsendsize;
 
345
  struct timeval lastrecvtime;
 
346
  size_t lastrecvsize;
 
347
  bool ftp_ssl;
 
348
  char *socks5proxy;
 
349
  bool tcp_nodelay;
 
350
  long req_retry;   /* number of retries */
 
351
  long retry_delay; /* delay between retries (in seconds) */
 
352
  long retry_maxtime; /* maximum time to keep retrying */
 
353
 
 
354
  char *tp_url; /* third party URL */
 
355
  char *tp_user; /* third party userpwd */
 
356
  struct curl_slist *tp_quote;
 
357
  struct curl_slist *tp_postquote;
 
358
  struct curl_slist *tp_prequote;
 
359
  char *ftp_account; /* for ACCT */
 
360
  int ftp_filemethod;
 
361
 
 
362
  bool ignorecl; /* --ignore-content-length */
 
363
};
 
364
 
 
365
#define WARN_PREFIX "Warning: "
 
366
#define WARN_TEXTWIDTH (79 - (int)strlen(WARN_PREFIX))
 
367
/* produce this text message to the user unless mute was selected */
 
368
static void warnf(struct Configurable *config, const char *fmt, ...)
 
369
{
 
370
  if(!(config->conf & CONF_MUTE)) {
 
371
    va_list ap;
 
372
    int len;
 
373
    char *ptr;
 
374
    char print_buffer[256];
 
375
 
 
376
    va_start(ap, fmt);
 
377
    va_start(ap, fmt);
 
378
    len = vsnprintf(print_buffer, sizeof(print_buffer), fmt, ap);
 
379
    va_end(ap);
 
380
 
 
381
    ptr = print_buffer;
 
382
    while(len > 0) {
 
383
      fputs(WARN_PREFIX, config->errors);
 
384
 
 
385
      if(len > (int)WARN_TEXTWIDTH) {
 
386
        int cut = WARN_TEXTWIDTH-1;
 
387
 
 
388
        while(!isspace((int)ptr[cut]) && cut) {
 
389
          cut--;
 
390
        }
 
391
 
 
392
        fwrite(ptr, cut + 1, 1, config->errors);
 
393
        fputs("\n", config->errors);
 
394
        ptr += cut+1; /* skip the space too */
 
395
        len -= cut;
 
396
      }
 
397
      else {
 
398
        fputs(ptr, config->errors);
 
399
        len = 0;
 
400
      }
 
401
    }
 
402
  }
 
403
}
 
404
 
246
405
/*
247
406
 * This is the main global constructor for the app. Call this before
248
407
 * _any_ libcurl usage. If this fails, *NO* libcurl functions may be
262
421
  curl_global_cleanup();
263
422
}
264
423
 
265
 
static int SetHTTPrequest(HttpReq req, HttpReq *store)
 
424
static int SetHTTPrequest(struct Configurable *config,
 
425
                          HttpReq req, HttpReq *store)
266
426
{
267
427
  if((*store == HTTPREQ_UNSPEC) ||
268
428
     (*store == req)) {
269
429
    *store = req;
270
430
    return 0;
271
431
  }
272
 
  fprintf(stderr, "You can only select one HTTP request!\n");
 
432
  warnf(config, "You can only select one HTTP request!\n");
273
433
  return 1;
274
434
}
275
435
 
306
466
#define GETOUT_UPLOAD  (1<<3)   /* if set, -T has been used */
307
467
#define GETOUT_NOUPLOAD  (1<<4) /* if set, -T "" has been used */
308
468
 
309
 
typedef enum {
310
 
    TRACE_BIN,   /* tcpdump inspired look */
311
 
    TRACE_ASCII, /* like *BIN but without the hex output */
312
 
    TRACE_PLAIN  /* -v/--verbose type */
313
 
} trace;
314
 
 
315
469
static void help(void)
316
470
{
317
471
  int i;
320
474
    "Options: (H) means HTTP/HTTPS only, (F) means FTP only",
321
475
    " -a/--append        Append to target file when uploading (F)",
322
476
    " -A/--user-agent <string> User-Agent to send to server (H)",
323
 
    "    --anyauth       Tell curl to choose authentication method (H)",
 
477
    "    --anyauth       Pick \"any\" authentication method (H)",
324
478
    " -b/--cookie <name=string/file> Cookie string or file to read cookies from (H)",
325
 
    "    --basic         Enable HTTP Basic Authentication (H)",
 
479
    "    --basic         Use HTTP Basic Authentication (H)",
326
480
    " -B/--use-ascii     Use ASCII/text transfer",
327
481
    " -c/--cookie-jar <file> Write cookies to this file after operation (H)",
328
482
    " -C/--continue-at <offset> Resumed transfer offset",
329
483
    " -d/--data <data>   HTTP POST data (H)",
330
 
    "    --data-ascii <data>   HTTP POST ASCII data (H)",
331
 
    "    --data-binary <data>  HTTP POST binary data (H)",
332
 
    "    --negotiate     Enable HTTP Negotiate Authentication (H)",
333
 
    "    --digest        Enable HTTP Digest Authentication (H)",
334
 
    "    --disable-eprt  Prevent curl from using EPRT or LPRT (F)",
335
 
    "    --disable-epsv  Prevent curl from using EPSV (F)",
 
484
    "    --data-ascii <data>  HTTP POST ASCII data (H)",
 
485
    "    --data-binary <data> HTTP POST binary data (H)",
 
486
    "    --negotiate     Use HTTP Negotiate Authentication (H)",
 
487
    "    --digest        Use HTTP Digest Authentication (H)",
 
488
    "    --disable-eprt  Inhibit using EPRT or LPRT (F)",
 
489
    "    --disable-epsv  Inhibit using EPSV (F)",
336
490
    " -D/--dump-header <file> Write the headers to this file",
337
491
    "    --egd-file <file> EGD socket path for random data (SSL)",
338
 
    "    --tcp-nodelay   Set the TCP_NODELAY option",
 
492
    "    --tcp-nodelay   Use the TCP_NODELAY option",
339
493
#ifdef USE_ENVIRONMENT
340
 
    "    --environment   Write result codes to environment variables (RISC OS)",
 
494
    "    --environment   Write results to environment variables (RISC OS)",
341
495
#endif
342
496
    " -e/--referer       Referer URL (H)",
343
497
    " -E/--cert <cert[:passwd]> Client certificate file and password (SSL)",
354
508
    "    --connect-timeout <seconds> Maximum time allowed for connection",
355
509
    "    --create-dirs   Create necessary local directory hierarchy",
356
510
    "    --crlf          Convert LF to CRLF in upload",
357
 
    " -f/--fail          Fail silently (no output at all) on errors (H)",
 
511
    " -f/--fail          Fail silently (no output at all) on HTTP errors (H)",
358
512
    "    --ftp-create-dirs Create the remote dirs if not present (F)",
359
 
    "    --ftp-pasv      Use PASV instead of PORT (F)",
 
513
    "    --ftp-pasv      Use PASV/EPSV instead of PORT (F)",
 
514
    "    --ftp-skip-pasv-ip Skip the IP address for PASV (F)\n"
360
515
    "    --ftp-ssl       Enable SSL/TLS for the ftp transfer (F)",
361
516
    " -F/--form <name=content> Specify HTTP multipart POST data (H)",
362
517
    "    --form-string <name=string> Specify HTTP multipart POST data (H)",
364
519
    " -G/--get           Send the -d data with a HTTP GET (H)",
365
520
    " -h/--help          This help text",
366
521
    " -H/--header <line> Custom header to pass to server (H)",
 
522
    "    --ignore-content-length  Ignore the HTTP Content-Length header",
367
523
    " -i/--include       Include protocol headers in the output (H/F)",
368
524
    " -I/--head          Show document info only",
369
525
    " -j/--junk-session-cookies Ignore session cookies read from file (H)",
370
526
    "    --interface <interface> Specify network interface to use",
371
527
    "    --krb4 <level>  Enable krb4 with specified security level (F)",
372
 
    " -k/--insecure      Allow curl to connect to SSL sites without certs (H)",
 
528
    " -k/--insecure      Allow connections to SSL sites without certs (H)",
373
529
    " -K/--config        Specify which config file to read",
374
530
    " -l/--list-only     List only names of an FTP directory (F)",
375
531
    "    --limit-rate <rate> Limit transfer speed to this rate",
382
538
    " -M/--manual        Display the full manual",
383
539
    " -n/--netrc         Must read .netrc for user name and password",
384
540
    "    --netrc-optional Use either .netrc or URL; overrides -n",
385
 
    "    --ntlm          Enable HTTP NTLM authentication (H)",
 
541
    "    --ntlm          Use HTTP NTLM authentication (H)",
386
542
    " -N/--no-buffer     Disable buffering of the output stream",
387
543
    " -o/--output <file> Write output to <file> instead of stdout",
388
544
    " -O/--remote-name   Write output to a file named as the remote file",
389
545
    " -p/--proxytunnel   Operate through a HTTP proxy tunnel (using CONNECT)",
390
 
    "    --proxy-anyauth  Let curl pick proxy authentication method (H)",
391
 
    "    --proxy-basic   Enable Basic authentication on the proxy (H)",
392
 
    "    --proxy-digest  Enable Digest authentication on the proxy (H)",
393
 
    "    --proxy-ntlm    Enable NTLM authentication on the proxy (H)",
 
546
    "    --proxy-anyauth Pick \"any\" proxy authentication method (H)",
 
547
    "    --proxy-basic   Use Basic authentication on the proxy (H)",
 
548
    "    --proxy-digest  Use Digest authentication on the proxy (H)",
 
549
    "    --proxy-ntlm    Use NTLM authentication on the proxy (H)",
394
550
    " -P/--ftp-port <address> Use PORT with address instead of PASV (F)",
395
551
    " -q                 If used as the first parameter disables .curlrc",
396
552
    " -Q/--quote <cmd>   Send command(s) to server before file transfer (F)",
450
606
  bool extraparam;
451
607
};
452
608
 
453
 
struct Configurable {
454
 
  bool remote_time;
455
 
  char *random_file;
456
 
  char *egd_file;
457
 
  char *useragent;
458
 
  char *cookie;     /* single line with specified cookies */
459
 
  char *cookiejar;  /* write to this file */
460
 
  char *cookiefile; /* read from this file */
461
 
  bool cookiesession; /* new session? */
462
 
  bool encoding;    /* Accept-Encoding please */
463
 
  long authtype;    /* auth bitmask */
464
 
  bool use_resume;
465
 
  bool resume_from_current;
466
 
  bool disable_epsv;
467
 
  bool disable_eprt;
468
 
  curl_off_t resume_from;
469
 
  char *postfields;
470
 
  long postfieldsize;
471
 
  char *referer;
472
 
  long timeout;
473
 
  long connecttimeout;
474
 
  long maxredirs;
475
 
  curl_off_t max_filesize;
476
 
  char *headerfile;
477
 
  char *ftpport;
478
 
  char *iface;
479
 
  unsigned short porttouse;
480
 
  char *range;
481
 
  long low_speed_limit;
482
 
  long low_speed_time;
483
 
  bool showerror;
484
 
  char *userpwd;
485
 
  char *proxyuserpwd;
486
 
  char *proxy;
487
 
  bool proxytunnel;
488
 
  long conf;
489
 
  struct getout *url_list; /* point to the first node */
490
 
  struct getout *url_last; /* point to the last/current node */
491
 
  struct getout *url_get;  /* point to the node to fill in URL */
492
 
  struct getout *url_out;  /* point to the node to fill in outfile */
493
 
  char *cipher_list;
494
 
  char *cert;
495
 
  char *cert_type;
496
 
  char *cacert;
497
 
  char *capath;
498
 
  char *key;
499
 
  char *key_type;
500
 
  char *key_passwd;
501
 
  char *engine;
502
 
  bool list_engines;
503
 
  bool crlf;
504
 
  char *customrequest;
505
 
  char *krb4level;
506
 
  char *trace_dump; /* file to dump the network trace to, or NULL */
507
 
  FILE *trace_stream;
508
 
  bool trace_fopened;
509
 
  trace tracetype;
510
 
  bool tracetime; /* include timestamp? */
511
 
  long httpversion;
512
 
  bool progressmode;
513
 
  bool nobuffer;
514
 
  bool globoff;
515
 
  bool use_httpget;
516
 
  bool insecure_ok; /* set TRUE to allow insecure SSL connects */
517
 
  bool create_dirs;
518
 
  bool ftp_create_dirs;
519
 
  bool proxyntlm;
520
 
  bool proxydigest;
521
 
  bool proxybasic;
522
 
  bool proxyanyauth;
523
 
  char *writeout; /* %-styled format string to output */
524
 
  bool writeenv; /* write results to environment, if available */
525
 
  FILE *errors; /* if stderr redirect is requested */
526
 
  bool errors_fopened;
527
 
  struct curl_slist *quote;
528
 
  struct curl_slist *postquote;
529
 
  struct curl_slist *prequote;
530
 
  long ssl_version;
531
 
  long ip_version;
532
 
  curl_TimeCond timecond;
533
 
  time_t condtime;
534
 
  struct curl_slist *headers;
535
 
  struct curl_httppost *httppost;
536
 
  struct curl_httppost *last_post;
537
 
  struct curl_slist *telnet_options;
538
 
  HttpReq httpreq;
539
 
 
540
 
  /* for bandwidth limiting features: */
541
 
  curl_off_t sendpersecond; /* send to peer */
542
 
  curl_off_t recvpersecond; /* receive from peer */
543
 
  struct timeval lastsendtime;
544
 
  size_t lastsendsize;
545
 
  struct timeval lastrecvtime;
546
 
  size_t lastrecvsize;
547
 
  bool ftp_ssl;
548
 
  char *socks5proxy;
549
 
  bool tcp_nodelay;
550
 
  long req_retry;   /* number of retries */
551
 
  long retry_delay; /* delay between retries (in seconds) */
552
 
  long retry_maxtime; /* maximum time to keep retrying */
553
 
 
554
 
  char *tp_url; /* third party URL */
555
 
  char *tp_user; /* third party userpwd */
556
 
  struct curl_slist *tp_quote;
557
 
  struct curl_slist *tp_postquote;
558
 
  struct curl_slist *tp_prequote;
559
 
  char *ftp_account; /* for ACCT */
560
 
};
561
 
 
562
609
/* global variable to hold info about libcurl */
563
610
static curl_version_info_data *curlinfo;
564
611
 
814
861
#define FORM_FILE_SEPARATOR ','
815
862
#define FORM_TYPE_SEPARATOR ';'
816
863
 
817
 
static int formparse(char *input,
 
864
static int formparse(struct Configurable *config,
 
865
                     char *input,
818
866
                     struct curl_httppost **httppost,
819
867
                     struct curl_httppost **last_post,
820
868
                     bool literal_value)
890
938
              /* verify that this is a fine type specifier */
891
939
              if(2 != sscanf(type, "%127[^/]/%127[^;,\n]",
892
940
                             major, minor)) {
893
 
                fprintf(stderr, "Illegally formatted content-type field!\n");
 
941
                warnf(config, "Illegally formatted content-type field!\n");
894
942
                free(contents);
895
943
                FreeMultiInfo (multi_start);
896
944
                return 2; /* illegal content-type syntax! */
939
987
 
940
988
        if (!AddMultiFiles (contp, type, filename, &multi_start,
941
989
                            &multi_current)) {
942
 
          fprintf(stderr, "Error building form post!\n");
 
990
          warnf(config, "Error building form post!\n");
943
991
          free(contents);
944
992
          FreeMultiInfo (multi_start);
945
993
          return 3;
976
1024
        if (curl_formadd(httppost, last_post,
977
1025
                         CURLFORM_COPYNAME, name,
978
1026
                         CURLFORM_ARRAY, forms, CURLFORM_END) != 0) {
979
 
          fprintf(stderr, "curl_formadd failed!\n");
 
1027
          warnf(config, "curl_formadd failed!\n");
980
1028
          free(forms);
981
1029
          free(contents);
982
1030
          return 5;
1008
1056
 
1009
1057
        if (curl_formadd(httppost, last_post,
1010
1058
                         CURLFORM_ARRAY, info, CURLFORM_END ) != 0) {
1011
 
          fprintf(stderr, "curl_formadd failed, possibly the file %s is bad!\n",
1012
 
                  contp+1);
 
1059
          warnf(config, "curl_formadd failed, possibly the file %s is bad!\n",
 
1060
                contp+1);
1013
1061
          free(contents);
1014
1062
          return 6;
1015
1063
        }
1021
1069
        info[i].option = CURLFORM_END;
1022
1070
        if (curl_formadd(httppost, last_post,
1023
1071
                         CURLFORM_ARRAY, info, CURLFORM_END) != 0) {
1024
 
          fprintf(stderr, "curl_formadd failed!\n");
 
1072
          warnf(config, "curl_formadd failed!\n");
1025
1073
          free(contents);
1026
1074
          return 7;
1027
1075
        }
1030
1078
 
1031
1079
  }
1032
1080
  else {
1033
 
    fprintf(stderr, "Illegally formatted input field!\n");
 
1081
    warnf(config, "Illegally formatted input field!\n");
1034
1082
    return 1;
1035
1083
  }
1036
1084
  free(contents);
1197
1245
  return PARAM_OK;
1198
1246
}
1199
1247
 
 
1248
static int ftpfilemethod(struct Configurable *config, char *str)
 
1249
{
 
1250
  if(strequal("singlecwd", str))
 
1251
    return 3;
 
1252
  if(strequal("nocwd", str))
 
1253
    return 2;
 
1254
  if(strequal("multicwd", str))
 
1255
    return 1;
 
1256
  warnf(config, "unrecognized ftp file method '%s', using default\n", str);
 
1257
  return 1;
 
1258
}
 
1259
 
1200
1260
static ParameterError getparameter(char *flag, /* f or -long-flag */
1201
1261
                                   char *nextarg, /* NULL if unset */
1202
1262
                                   bool *usedarg, /* set to TRUE if the arg
1267
1327
    {"$m", "ftp-account", TRUE},
1268
1328
    {"$n", "proxy-anyauth", FALSE},
1269
1329
    {"$o", "trace-time", FALSE},
 
1330
    {"$p", "ignore-content-length", FALSE},
 
1331
    {"$q", "ftp-skip-pasv-ip", FALSE},
 
1332
    {"$r", "ftp-method", TRUE},
1270
1333
 
1271
1334
    {"0", "http1.0",     FALSE},
1272
1335
    {"1", "tlsv1",       FALSE},
1387
1450
    }
1388
1451
    *usedarg = FALSE; /* default is that we don't use the arg */
1389
1452
 
1390
 
#if 0
1391
 
    fprintf(stderr, "OPTION: %c %s\n", letter, nextarg?nextarg:"<null>");
1392
 
#endif
1393
1453
    if(hit < 0) {
1394
1454
      for(j=0; j< sizeof(aliases)/sizeof(aliases[0]); j++) {
1395
1455
        if(letter == aliases[j].letter[0]) {
1451
1511
          /* We support G, M, K too */
1452
1512
          char *unit;
1453
1513
          curl_off_t value = curlx_strtoofft(nextarg, &unit, 0);
1454
 
          switch(nextarg[strlen(nextarg)-1]) {
 
1514
 
 
1515
          if(strlen(unit) != 1)
 
1516
            unit=(char *)"w"; /* unsupported */
 
1517
 
 
1518
          switch(*unit) {
1455
1519
          case 'G':
1456
1520
          case 'g':
1457
1521
            value *= 1024*1024*1024;
1464
1528
          case 'k':
1465
1529
            value *= 1024;
1466
1530
            break;
 
1531
          case 'b':
 
1532
          case 'B':
 
1533
            /* for plain bytes, leave as-is */
 
1534
            break;
 
1535
          default:
 
1536
            warnf(config, "unsupported rate unit. Use G, M, K or B!\n");
 
1537
            return PARAM_BAD_USE;
1467
1538
          }
1468
1539
          config->recvpersecond = value;
1469
1540
          config->sendpersecond = value;
1533
1604
 
1534
1605
      case 'v': /* --stderr */
1535
1606
        if(strcmp(nextarg, "-")) {
1536
 
          config->errors = fopen(nextarg, "wt");
1537
 
          config->errors_fopened = TRUE;
 
1607
          FILE *newfile = fopen(nextarg, "wt");
 
1608
          if(!config->errors)
 
1609
            warnf(config, "Failed to open %s!\n", nextarg);
 
1610
          else {
 
1611
            config->errors = newfile;
 
1612
            config->errors_fopened = TRUE;
 
1613
          }
1538
1614
        }
1539
1615
        else
1540
1616
          config->errors = stdout;
1658
1734
      case 'o': /* --trace-time */
1659
1735
        config->tracetime ^= TRUE;
1660
1736
        break;
 
1737
      case 'p': /* --ignore-content-length */
 
1738
        config->ignorecl ^= TRUE;
 
1739
        break;
 
1740
      case 'q': /* --ftp-skip-pasv-ip */
 
1741
        config->ftp_skip_ip ^= TRUE;
 
1742
        break;
 
1743
      case 'r': /* --ftp-method (undocumented at this point) */
 
1744
        config->ftp_filemethod = ftpfilemethod(config, nextarg);
 
1745
        break;
1661
1746
      }
1662
1747
      break;
1663
1748
    case '#': /* --progress-bar */
1740
1825
 
1741
1826
          nextarg++; /* pass the @ */
1742
1827
 
1743
 
          if(curlx_strequal("-", nextarg))
 
1828
          if(curlx_strequal("-", nextarg)) {
1744
1829
            file = stdin;
1745
 
          else
 
1830
#ifdef O_BINARY
 
1831
            if(subletter == 'b') /* forced binary */
 
1832
              setmode(fileno(stdin), O_BINARY);
 
1833
#endif
 
1834
          }
 
1835
          else {
1746
1836
            file = fopen(nextarg, "rb");
 
1837
            if(!file)
 
1838
              warnf(config, "Couldn't read data from file \"%s\", this makes "
 
1839
                    "an empty POST.\n", nextarg);
 
1840
          }
1747
1841
 
1748
1842
          if(subletter == 'b') /* forced binary */
1749
1843
            postdata = file2memory(file, &config->postfieldsize);
1750
1844
          else
1751
1845
            postdata = file2string(file);
 
1846
 
1752
1847
          if(file && (file != stdin))
1753
1848
            fclose(file);
 
1849
 
 
1850
          if(!postdata) {
 
1851
            /* no data from the file, point to a zero byte string to make this
 
1852
               get sent as a POST anyway */
 
1853
            postdata=strdup("");
 
1854
          }
1754
1855
        }
1755
1856
        else {
1756
1857
          GetStr(&postdata, nextarg);
1856
1957
    case 'F':
1857
1958
      /* "form data" simulation, this is a little advanced so lets do our best
1858
1959
         to sort this out slowly and carefully */
1859
 
      if(formparse(nextarg,
 
1960
      if(formparse(config,
 
1961
                   nextarg,
1860
1962
                   &config->httppost,
1861
1963
                   &config->last_post,
1862
 
                   subletter=='s')) /* 's' means literal string */
 
1964
                   (bool) (subletter=='s'))) /* 's' means literal string */
1863
1965
        return PARAM_BAD_USE;
1864
 
      if(SetHTTPrequest(HTTPREQ_POST, &config->httpreq))
 
1966
      if(SetHTTPrequest(config, HTTPREQ_POST, &config->httpreq))
1865
1967
        return PARAM_BAD_USE;
1866
1968
      break;
1867
1969
 
1897
1999
         (config->conf&(CONF_HEADER|CONF_NOBODY)) ) {
1898
2000
        /* one of them weren't set, set both */
1899
2001
        config->conf |= (CONF_HEADER|CONF_NOBODY);
1900
 
        if(SetHTTPrequest(HTTPREQ_HEAD, &config->httpreq))
 
2002
        if(SetHTTPrequest(config, HTTPREQ_HEAD, &config->httpreq))
1901
2003
          return PARAM_BAD_USE;
1902
2004
      }
1903
2005
      else {
1904
2006
        /* both were set, clear both */
1905
2007
        config->conf &= ~(CONF_HEADER|CONF_NOBODY);
1906
 
        if(SetHTTPrequest(HTTPREQ_GET, &config->httpreq))
 
2008
        if(SetHTTPrequest(config, HTTPREQ_GET, &config->httpreq))
1907
2009
          return PARAM_BAD_USE;
1908
2010
      }
1909
2011
      break;
1936
2038
      hugehelp();
1937
2039
      return PARAM_HELP_REQUESTED;
1938
2040
#else
1939
 
      fprintf(stderr,
1940
 
              "curl: built-in manual was disabled at build-time!\n");
 
2041
      warnf(config,
 
2042
            "built-in manual was disabled at build-time!\n");
1941
2043
      return PARAM_OPTION_UNKNOWN;
1942
2044
#endif
1943
2045
    case 'n':
2028
2130
        return err;
2029
2131
      break;
2030
2132
    case 'r':
2031
 
      /* byte range requested */
2032
 
      GetStr(&config->range, nextarg);
 
2133
      /* Specifying a range WITHOUT A DASH will create an illegal HTTP range
 
2134
         (and won't actually be range by definition). The man page previously
 
2135
         claimed that to be a good way, why this code is added to work-around
 
2136
         it. */
 
2137
      if(!strchr(nextarg, '-')) {
 
2138
        char buffer[32];
 
2139
        curl_off_t off;
 
2140
        warnf(config,
 
2141
              "A specfied range MUST include at least one dash (-). "
 
2142
              "Appending one for you!\n");
 
2143
        off = curlx_strtoofft(nextarg, NULL, 10);
 
2144
        snprintf(buffer, sizeof(buffer), CURL_FORMAT_OFF_T "-", off);
 
2145
        GetStr(&config->range, buffer);
 
2146
      }
 
2147
      else
 
2148
        /* byte range requested */
 
2149
        GetStr(&config->range, nextarg);
 
2150
 
2033
2151
      break;
2034
2152
    case 'R':
2035
2153
      /* use remote file's time */
2150
2268
        else
2151
2269
          file = fopen(nextarg, "r");
2152
2270
        config->writeout = file2string(file);
 
2271
        if(!config->writeout)
 
2272
          warnf(config, "Failed to read %s", file);
2153
2273
        if(file && (file != stdin))
2154
2274
          fclose(file);
2155
2275
      }
2205
2325
        if(-1 == stat(nextarg, &statbuf)) {
2206
2326
          /* failed, remove time condition */
2207
2327
          config->timecond = CURL_TIMECOND_NONE;
2208
 
          fprintf(stderr,
2209
 
                  "Warning: Illegal date format for -z/--timecond and not "
2210
 
                  "a file name.\n"
2211
 
                  "         See curl_getdate(3) for valid date syntax.\n");
 
2328
          warnf(config,
 
2329
                "Illegal date format for -z/--timecond (and not "
 
2330
                "a file name). Disabling time condition. "
 
2331
                "See curl_getdate(3) for valid date syntax.\n");
2212
2332
        }
2213
2333
        else {
2214
2334
          /* pull the time out from the file */
2421
2541
        }
2422
2542
        if(PARAM_HELP_REQUESTED != res) {
2423
2543
          const char *reason = param2text(res);
2424
 
          fprintf(stderr, "%s:%d: warning: '%s' %s\n",
2425
 
                  filename, lineno, option, reason);
 
2544
          warnf(config, "%s:%d: warning: '%s' %s\n",
 
2545
                filename, lineno, option, reason);
2426
2546
        }
2427
2547
      }
2428
2548
 
2485
2605
  if(out && !out->stream) {
2486
2606
    /* open file for writing */
2487
2607
    out->stream=fopen(out->filename, "wb");
2488
 
    if(!out->stream)
 
2608
    if(!out->stream) {
 
2609
      warnf(config, "Failed to create the file %s\n", out->filename);
2489
2610
      return -1; /* failure */
 
2611
    }
2490
2612
  }
2491
2613
 
2492
2614
  if(config->recvpersecond) {
2817
2939
  const char *text;
2818
2940
  struct timeval tv;
2819
2941
  struct tm *now;
2820
 
  char timebuf[15];
 
2942
  char timebuf[20];
2821
2943
 
2822
2944
  (void)handle; /* prevent compiler warning */
2823
2945
 
2824
2946
  tv = curlx_tvnow();
2825
2947
  now = localtime(&tv.tv_sec);  /* not multithread safe but we don't care */
2826
2948
  if(config->tracetime)
2827
 
    snprintf(timebuf, sizeof(timebuf), "%02d:%02d:%02d.%02d ",
2828
 
             now->tm_hour, now->tm_min, now->tm_sec,
2829
 
             tv.tv_usec/10000);
 
2949
    snprintf(timebuf, sizeof(timebuf), "%02d:%02d:%02d.%06d ",
 
2950
             now->tm_hour, now->tm_min, now->tm_sec, tv.tv_usec);
2830
2951
  else
2831
2952
    timebuf[0]=0;
2832
2953
 
3118
3239
  config->create_dirs=FALSE;
3119
3240
  config->lastrecvtime = curlx_tvnow();
3120
3241
  config->lastsendtime = curlx_tvnow();
 
3242
  config->maxredirs = DEFAULT_MAXREDIRS;
3121
3243
 
3122
3244
  if(argc>1 &&
3123
3245
     (!curlx_strnequal("--", argv[1], 2) && (argv[1][0] == '-')) &&
3234
3356
      httpgetfields = strdup(config->postfields);
3235
3357
      free(config->postfields);
3236
3358
      config->postfields = NULL;
3237
 
      if(SetHTTPrequest((config->conf&CONF_NOBODY?HTTPREQ_HEAD:HTTPREQ_GET),
 
3359
      if(SetHTTPrequest(config,
 
3360
                        (config->conf&CONF_NOBODY?HTTPREQ_HEAD:HTTPREQ_GET),
3238
3361
                        &config->httpreq)) {
3239
3362
        free(httpgetfields);
3240
3363
        return PARAM_BAD_USE;
3241
3364
      }
3242
3365
    }
3243
3366
    else {
3244
 
      if(SetHTTPrequest(HTTPREQ_SIMPLEPOST, &config->httpreq))
 
3367
      if(SetHTTPrequest(config, HTTPREQ_SIMPLEPOST, &config->httpreq))
3245
3368
        return PARAM_BAD_USE;
3246
3369
    }
3247
3370
  }
3408
3531
            free(storefile);
3409
3532
            if(!outfile) {
3410
3533
              /* bad globbing */
3411
 
              fprintf(stderr, "bad output glob!\n");
 
3534
              warnf(config, "bad output glob!\n");
3412
3535
              free(url);
3413
3536
              res = CURLE_FAILED_INIT;
3414
3537
              break;
3531
3654
 
3532
3655
        }
3533
3656
        else if(uploadfile && curlx_strequal(uploadfile, "-")) {
 
3657
#ifdef O_BINARY
 
3658
          setmode(fileno(stdin), O_BINARY);
 
3659
#endif
3534
3660
          infd = stdin;
3535
3661
        }
3536
3662
 
3706
3832
          curl_easy_setopt(curl, CURLOPT_FILETIME, TRUE);
3707
3833
        }
3708
3834
 
3709
 
        if (config->maxredirs)
3710
 
          curl_easy_setopt(curl, CURLOPT_MAXREDIRS, config->maxredirs);
3711
 
        else
3712
 
          curl_easy_setopt(curl, CURLOPT_MAXREDIRS, DEFAULT_MAXREDIRS);
3713
 
 
 
3835
        curl_easy_setopt(curl, CURLOPT_MAXREDIRS, config->maxredirs);
3714
3836
        curl_easy_setopt(curl, CURLOPT_CRLF, config->crlf);
3715
3837
        curl_easy_setopt(curl, CURLOPT_QUOTE, config->quote);
3716
3838
        curl_easy_setopt(curl, CURLOPT_POSTQUOTE, config->postquote);
3836
3958
        curl_easy_setopt(curl, CURLOPT_SOURCE_QUOTE, config->tp_quote);
3837
3959
        curl_easy_setopt(curl, CURLOPT_FTP_ACCOUNT, config->ftp_account);
3838
3960
 
 
3961
        curl_easy_setopt(curl, CURLOPT_IGNORE_CONTENT_LENGTH, config->ignorecl);
 
3962
 
 
3963
        /* curl 7.14.2 */
 
3964
        curl_easy_setopt(curl, CURLOPT_FTP_SKIP_PASV_IP, config->ftp_skip_ip);
 
3965
 
 
3966
        /* curl 7.15.1 */
 
3967
        curl_easy_setopt(curl, CURLOPT_FTP_FILEMETHOD, config->ftp_filemethod);
 
3968
 
3839
3969
        retry_numretries = config->req_retry;
3840
3970
 
3841
3971
        retrystart = curlx_tvnow();
3902
4032
            }
3903
4033
 
3904
4034
            if(retry) {
3905
 
              if(!(config->conf&CONF_MUTE)) {
3906
 
                static const char * const m[]={NULL,
3907
 
                                              "timeout",
3908
 
                                              "HTTP error",
3909
 
                                              "FTP error"
3910
 
                };
3911
 
                fprintf(stderr, "Transient problem: %s\n"
3912
 
                        "Will retry in %ld seconds. "
3913
 
                        "%ld retries left.\n",
3914
 
                        m[retry],
3915
 
                        retry_sleep/1000,
3916
 
                        retry_numretries);
3917
 
              }
 
4035
              static const char * const m[]={NULL,
 
4036
                                             "timeout",
 
4037
                                             "HTTP error",
 
4038
                                             "FTP error"
 
4039
              };
 
4040
              warnf(config, "Transient problem: %s "
 
4041
                    "Will retry in %ld seconds. "
 
4042
                    "%ld retries left.\n",
 
4043
                    m[retry],
 
4044
                    retry_sleep/1000,
 
4045
                    retry_numretries);
 
4046
 
3918
4047
              go_sleep(retry_sleep);
3919
4048
              retry_numretries--;
3920
4049
              if(!config->retry_delay) {
4081
4210
  if (config->engine)
4082
4211
    free(config->engine);
4083
4212
 
 
4213
  /* cleanup the curl handle! */
 
4214
  curl_easy_cleanup(curl);
 
4215
 
4084
4216
  if(config->headerfile && !headerfilep && heads.stream)
4085
4217
    fclose(heads.stream);
4086
4218
 
4087
4219
  if(allocuseragent)
4088
4220
    free(config->useragent);
4089
4221
 
4090
 
  /* cleanup the curl handle! */
4091
 
  curl_easy_cleanup(curl);
4092
 
 
4093
4222
  if(config->trace_fopened && config->trace_stream)
4094
4223
    fclose(config->trace_stream);
4095
4224
 
4128
4257
  struct Configurable config;
4129
4258
  memset(&config, 0, sizeof(struct Configurable));
4130
4259
 
 
4260
  config.errors = stderr; /* default errors to stderr */
 
4261
 
4131
4262
  checkfds();
4132
4263
 
4133
4264
  res = operate(&config, argc, argv);