~ubuntu-branches/ubuntu/trusty/curl/trusty-updates

« back to all changes in this revision

Viewing changes to .pc/CVE-2014-3707.patch/lib/formdata.c

  • Committer: Package Import Robot
  • Author(s): Marc Deslauriers
  • Date: 2014-11-06 10:53:58 UTC
  • Revision ID: package-import@ubuntu.com-20141106105358-e90s20tv3eobuukd
Tags: 7.35.0-1ubuntu2.2
* SECURITY UPDATE: sensitive data disclosure via duphandle read out of
  bounds
  - debian/patches/CVE-2014-3707.patch: properly copy memory aread in
    lib/formdata.c, lib/strdup.{c,h}, lib/url.c, lib/urldata.h,
    src/Makefile.inc, src/tool_setup.h, src/tool_strdup.{c,h}.
  - CVE-2014-3707

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
 *                                  _   _ ____  _
 
3
 *  Project                     ___| | | |  _ \| |
 
4
 *                             / __| | | | |_) | |
 
5
 *                            | (__| |_| |  _ <| |___
 
6
 *                             \___|\___/|_| \_\_____|
 
7
 *
 
8
 * Copyright (C) 1998 - 2013, 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 http://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
 
 
23
#include "curl_setup.h"
 
24
 
 
25
#include <curl/curl.h>
 
26
 
 
27
#if !defined(CURL_DISABLE_HTTP) || defined(USE_SSLEAY)
 
28
 
 
29
#if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME)
 
30
#include <libgen.h>
 
31
#endif
 
32
 
 
33
#include "urldata.h" /* for struct SessionHandle */
 
34
#include "formdata.h"
 
35
#include "vtls/vtls.h"
 
36
#include "strequal.h"
 
37
#include "curl_memory.h"
 
38
#include "sendf.h"
 
39
 
 
40
#define _MPRINTF_REPLACE /* use our functions only */
 
41
#include <curl/mprintf.h>
 
42
 
 
43
/* The last #include file should be: */
 
44
#include "memdebug.h"
 
45
 
 
46
#endif  /* !defined(CURL_DISABLE_HTTP) || defined(USE_SSLEAY) */
 
47
 
 
48
#ifndef CURL_DISABLE_HTTP
 
49
 
 
50
#ifndef HAVE_BASENAME
 
51
static char *Curl_basename(char *path);
 
52
#define basename(x)  Curl_basename((x))
 
53
#endif
 
54
 
 
55
static size_t readfromfile(struct Form *form, char *buffer, size_t size);
 
56
static char *formboundary(struct SessionHandle *data);
 
57
 
 
58
/* What kind of Content-Type to use on un-specified files with unrecognized
 
59
   extensions. */
 
60
#define HTTPPOST_CONTENTTYPE_DEFAULT "application/octet-stream"
 
61
 
 
62
#define FORM_FILE_SEPARATOR ','
 
63
#define FORM_TYPE_SEPARATOR ';'
 
64
 
 
65
/***************************************************************************
 
66
 *
 
67
 * AddHttpPost()
 
68
 *
 
69
 * Adds a HttpPost structure to the list, if parent_post is given becomes
 
70
 * a subpost of parent_post instead of a direct list element.
 
71
 *
 
72
 * Returns newly allocated HttpPost on success and NULL if malloc failed.
 
73
 *
 
74
 ***************************************************************************/
 
75
static struct curl_httppost *
 
76
AddHttpPost(char *name, size_t namelength,
 
77
            char *value, size_t contentslength,
 
78
            char *buffer, size_t bufferlength,
 
79
            char *contenttype,
 
80
            long flags,
 
81
            struct curl_slist* contentHeader,
 
82
            char *showfilename, char *userp,
 
83
            struct curl_httppost *parent_post,
 
84
            struct curl_httppost **httppost,
 
85
            struct curl_httppost **last_post)
 
86
{
 
87
  struct curl_httppost *post;
 
88
  post = calloc(1, sizeof(struct curl_httppost));
 
89
  if(post) {
 
90
    post->name = name;
 
91
    post->namelength = (long)(name?(namelength?namelength:strlen(name)):0);
 
92
    post->contents = value;
 
93
    post->contentslength = (long)contentslength;
 
94
    post->buffer = buffer;
 
95
    post->bufferlength = (long)bufferlength;
 
96
    post->contenttype = contenttype;
 
97
    post->contentheader = contentHeader;
 
98
    post->showfilename = showfilename;
 
99
    post->userp = userp,
 
100
    post->flags = flags;
 
101
  }
 
102
  else
 
103
    return NULL;
 
104
 
 
105
  if(parent_post) {
 
106
    /* now, point our 'more' to the original 'more' */
 
107
    post->more = parent_post->more;
 
108
 
 
109
    /* then move the original 'more' to point to ourselves */
 
110
    parent_post->more = post;
 
111
  }
 
112
  else {
 
113
    /* make the previous point to this */
 
114
    if(*last_post)
 
115
      (*last_post)->next = post;
 
116
    else
 
117
      (*httppost) = post;
 
118
 
 
119
    (*last_post) = post;
 
120
  }
 
121
  return post;
 
122
}
 
123
 
 
124
/***************************************************************************
 
125
 *
 
126
 * AddFormInfo()
 
127
 *
 
128
 * Adds a FormInfo structure to the list presented by parent_form_info.
 
129
 *
 
130
 * Returns newly allocated FormInfo on success and NULL if malloc failed/
 
131
 * parent_form_info is NULL.
 
132
 *
 
133
 ***************************************************************************/
 
134
static FormInfo * AddFormInfo(char *value,
 
135
                              char *contenttype,
 
136
                              FormInfo *parent_form_info)
 
137
{
 
138
  FormInfo *form_info;
 
139
  form_info = calloc(1, sizeof(struct FormInfo));
 
140
  if(form_info) {
 
141
    if(value)
 
142
      form_info->value = value;
 
143
    if(contenttype)
 
144
      form_info->contenttype = contenttype;
 
145
    form_info->flags = HTTPPOST_FILENAME;
 
146
  }
 
147
  else
 
148
    return NULL;
 
149
 
 
150
  if(parent_form_info) {
 
151
    /* now, point our 'more' to the original 'more' */
 
152
    form_info->more = parent_form_info->more;
 
153
 
 
154
    /* then move the original 'more' to point to ourselves */
 
155
    parent_form_info->more = form_info;
 
156
  }
 
157
 
 
158
  return form_info;
 
159
}
 
160
 
 
161
/***************************************************************************
 
162
 *
 
163
 * ContentTypeForFilename()
 
164
 *
 
165
 * Provides content type for filename if one of the known types (else
 
166
 * (either the prevtype or the default is returned).
 
167
 *
 
168
 * Returns some valid contenttype for filename.
 
169
 *
 
170
 ***************************************************************************/
 
171
static const char *ContentTypeForFilename(const char *filename,
 
172
                                          const char *prevtype)
 
173
{
 
174
  const char *contenttype = NULL;
 
175
  unsigned int i;
 
176
  /*
 
177
   * No type was specified, we scan through a few well-known
 
178
   * extensions and pick the first we match!
 
179
   */
 
180
  struct ContentType {
 
181
    const char *extension;
 
182
    const char *type;
 
183
  };
 
184
  static const struct ContentType ctts[]={
 
185
    {".gif",  "image/gif"},
 
186
    {".jpg",  "image/jpeg"},
 
187
    {".jpeg", "image/jpeg"},
 
188
    {".txt",  "text/plain"},
 
189
    {".html", "text/html"},
 
190
    {".xml", "application/xml"}
 
191
  };
 
192
 
 
193
  if(prevtype)
 
194
    /* default to the previously set/used! */
 
195
    contenttype = prevtype;
 
196
  else
 
197
    contenttype = HTTPPOST_CONTENTTYPE_DEFAULT;
 
198
 
 
199
  if(filename) { /* in case a NULL was passed in */
 
200
    for(i=0; i<sizeof(ctts)/sizeof(ctts[0]); i++) {
 
201
      if(strlen(filename) >= strlen(ctts[i].extension)) {
 
202
        if(strequal(filename +
 
203
                    strlen(filename) - strlen(ctts[i].extension),
 
204
                    ctts[i].extension)) {
 
205
          contenttype = ctts[i].type;
 
206
          break;
 
207
        }
 
208
      }
 
209
    }
 
210
  }
 
211
  /* we have a contenttype by now */
 
212
  return contenttype;
 
213
}
 
214
 
 
215
/***************************************************************************
 
216
 *
 
217
 * memdup()
 
218
 *
 
219
 * Copies the 'source' data to a newly allocated buffer buffer (that is
 
220
 * returned). Uses buffer_length if not null, else uses strlen to determine
 
221
 * the length of the buffer to be copied
 
222
 *
 
223
 * Returns the new pointer or NULL on failure.
 
224
 *
 
225
 ***************************************************************************/
 
226
static char *memdup(const char *src, size_t buffer_length)
 
227
{
 
228
  size_t length;
 
229
  bool add = FALSE;
 
230
  char *buffer;
 
231
 
 
232
  if(buffer_length)
 
233
    length = buffer_length;
 
234
  else if(src) {
 
235
    length = strlen(src);
 
236
    add = TRUE;
 
237
  }
 
238
  else
 
239
    /* no length and a NULL src pointer! */
 
240
    return strdup("");
 
241
 
 
242
  buffer = malloc(length+add);
 
243
  if(!buffer)
 
244
    return NULL; /* fail */
 
245
 
 
246
  memcpy(buffer, src, length);
 
247
 
 
248
  /* if length unknown do null termination */
 
249
  if(add)
 
250
    buffer[length] = '\0';
 
251
 
 
252
  return buffer;
 
253
}
 
254
 
 
255
/***************************************************************************
 
256
 *
 
257
 * FormAdd()
 
258
 *
 
259
 * Stores a formpost parameter and builds the appropriate linked list.
 
260
 *
 
261
 * Has two principal functionalities: using files and byte arrays as
 
262
 * post parts. Byte arrays are either copied or just the pointer is stored
 
263
 * (as the user requests) while for files only the filename and not the
 
264
 * content is stored.
 
265
 *
 
266
 * While you may have only one byte array for each name, multiple filenames
 
267
 * are allowed (and because of this feature CURLFORM_END is needed after
 
268
 * using CURLFORM_FILE).
 
269
 *
 
270
 * Examples:
 
271
 *
 
272
 * Simple name/value pair with copied contents:
 
273
 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
 
274
 * CURLFORM_COPYCONTENTS, "value", CURLFORM_END);
 
275
 *
 
276
 * name/value pair where only the content pointer is remembered:
 
277
 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
 
278
 * CURLFORM_PTRCONTENTS, ptr, CURLFORM_CONTENTSLENGTH, 10, CURLFORM_END);
 
279
 * (if CURLFORM_CONTENTSLENGTH is missing strlen () is used)
 
280
 *
 
281
 * storing a filename (CONTENTTYPE is optional!):
 
282
 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
 
283
 * CURLFORM_FILE, "filename1", CURLFORM_CONTENTTYPE, "plain/text",
 
284
 * CURLFORM_END);
 
285
 *
 
286
 * storing multiple filenames:
 
287
 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
 
288
 * CURLFORM_FILE, "filename1", CURLFORM_FILE, "filename2", CURLFORM_END);
 
289
 *
 
290
 * Returns:
 
291
 * CURL_FORMADD_OK             on success
 
292
 * CURL_FORMADD_MEMORY         if the FormInfo allocation fails
 
293
 * CURL_FORMADD_OPTION_TWICE   if one option is given twice for one Form
 
294
 * CURL_FORMADD_NULL           if a null pointer was given for a char
 
295
 * CURL_FORMADD_MEMORY         if the allocation of a FormInfo struct failed
 
296
 * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used
 
297
 * CURL_FORMADD_INCOMPLETE     if the some FormInfo is not complete (or error)
 
298
 * CURL_FORMADD_MEMORY         if a HttpPost struct cannot be allocated
 
299
 * CURL_FORMADD_MEMORY         if some allocation for string copying failed.
 
300
 * CURL_FORMADD_ILLEGAL_ARRAY  if an illegal option is used in an array
 
301
 *
 
302
 ***************************************************************************/
 
303
 
 
304
static
 
305
CURLFORMcode FormAdd(struct curl_httppost **httppost,
 
306
                     struct curl_httppost **last_post,
 
307
                     va_list params)
 
308
{
 
309
  FormInfo *first_form, *current_form, *form = NULL;
 
310
  CURLFORMcode return_value = CURL_FORMADD_OK;
 
311
  const char *prevtype = NULL;
 
312
  struct curl_httppost *post = NULL;
 
313
  CURLformoption option;
 
314
  struct curl_forms *forms = NULL;
 
315
  char *array_value=NULL; /* value read from an array */
 
316
 
 
317
  /* This is a state variable, that if TRUE means that we're parsing an
 
318
     array that we got passed to us. If FALSE we're parsing the input
 
319
     va_list arguments. */
 
320
  bool array_state = FALSE;
 
321
 
 
322
  /*
 
323
   * We need to allocate the first struct to fill in.
 
324
   */
 
325
  first_form = calloc(1, sizeof(struct FormInfo));
 
326
  if(!first_form)
 
327
    return CURL_FORMADD_MEMORY;
 
328
 
 
329
  current_form = first_form;
 
330
 
 
331
  /*
 
332
   * Loop through all the options set. Break if we have an error to report.
 
333
   */
 
334
  while(return_value == CURL_FORMADD_OK) {
 
335
 
 
336
    /* first see if we have more parts of the array param */
 
337
    if(array_state && forms) {
 
338
      /* get the upcoming option from the given array */
 
339
      option = forms->option;
 
340
      array_value = (char *)forms->value;
 
341
 
 
342
      forms++; /* advance this to next entry */
 
343
      if(CURLFORM_END == option) {
 
344
        /* end of array state */
 
345
        array_state = FALSE;
 
346
        continue;
 
347
      }
 
348
    }
 
349
    else {
 
350
      /* This is not array-state, get next option */
 
351
      option = va_arg(params, CURLformoption);
 
352
      if(CURLFORM_END == option)
 
353
        break;
 
354
    }
 
355
 
 
356
    switch (option) {
 
357
    case CURLFORM_ARRAY:
 
358
      if(array_state)
 
359
        /* we don't support an array from within an array */
 
360
        return_value = CURL_FORMADD_ILLEGAL_ARRAY;
 
361
      else {
 
362
        forms = va_arg(params, struct curl_forms *);
 
363
        if(forms)
 
364
          array_state = TRUE;
 
365
        else
 
366
          return_value = CURL_FORMADD_NULL;
 
367
      }
 
368
      break;
 
369
 
 
370
      /*
 
371
       * Set the Name property.
 
372
       */
 
373
    case CURLFORM_PTRNAME:
 
374
#ifdef CURL_DOES_CONVERSIONS
 
375
      /* Treat CURLFORM_PTR like CURLFORM_COPYNAME so that libcurl will copy
 
376
       * the data in all cases so that we'll have safe memory for the eventual
 
377
       * conversion.
 
378
       */
 
379
#else
 
380
      current_form->flags |= HTTPPOST_PTRNAME; /* fall through */
 
381
#endif
 
382
    case CURLFORM_COPYNAME:
 
383
      if(current_form->name)
 
384
        return_value = CURL_FORMADD_OPTION_TWICE;
 
385
      else {
 
386
        char *name = array_state?
 
387
          array_value:va_arg(params, char *);
 
388
        if(name)
 
389
          current_form->name = name; /* store for the moment */
 
390
        else
 
391
          return_value = CURL_FORMADD_NULL;
 
392
      }
 
393
      break;
 
394
    case CURLFORM_NAMELENGTH:
 
395
      if(current_form->namelength)
 
396
        return_value = CURL_FORMADD_OPTION_TWICE;
 
397
      else
 
398
        current_form->namelength =
 
399
          array_state?(size_t)array_value:(size_t)va_arg(params, long);
 
400
      break;
 
401
 
 
402
      /*
 
403
       * Set the contents property.
 
404
       */
 
405
    case CURLFORM_PTRCONTENTS:
 
406
      current_form->flags |= HTTPPOST_PTRCONTENTS; /* fall through */
 
407
    case CURLFORM_COPYCONTENTS:
 
408
      if(current_form->value)
 
409
        return_value = CURL_FORMADD_OPTION_TWICE;
 
410
      else {
 
411
        char *value =
 
412
          array_state?array_value:va_arg(params, char *);
 
413
        if(value)
 
414
          current_form->value = value; /* store for the moment */
 
415
        else
 
416
          return_value = CURL_FORMADD_NULL;
 
417
      }
 
418
      break;
 
419
    case CURLFORM_CONTENTSLENGTH:
 
420
      if(current_form->contentslength)
 
421
        return_value = CURL_FORMADD_OPTION_TWICE;
 
422
      else
 
423
        current_form->contentslength =
 
424
          array_state?(size_t)array_value:(size_t)va_arg(params, long);
 
425
      break;
 
426
 
 
427
      /* Get contents from a given file name */
 
428
    case CURLFORM_FILECONTENT:
 
429
      if(current_form->flags & (HTTPPOST_PTRCONTENTS|HTTPPOST_READFILE))
 
430
        return_value = CURL_FORMADD_OPTION_TWICE;
 
431
      else {
 
432
        const char *filename = array_state?
 
433
          array_value:va_arg(params, char *);
 
434
        if(filename) {
 
435
          current_form->value = strdup(filename);
 
436
          if(!current_form->value)
 
437
            return_value = CURL_FORMADD_MEMORY;
 
438
          else {
 
439
            current_form->flags |= HTTPPOST_READFILE;
 
440
            current_form->value_alloc = TRUE;
 
441
          }
 
442
        }
 
443
        else
 
444
          return_value = CURL_FORMADD_NULL;
 
445
      }
 
446
      break;
 
447
 
 
448
      /* We upload a file */
 
449
    case CURLFORM_FILE:
 
450
      {
 
451
        const char *filename = array_state?array_value:
 
452
          va_arg(params, char *);
 
453
 
 
454
        if(current_form->value) {
 
455
          if(current_form->flags & HTTPPOST_FILENAME) {
 
456
            if(filename) {
 
457
              char *fname = strdup(filename);
 
458
              if(!fname)
 
459
                return_value = CURL_FORMADD_MEMORY;
 
460
              else {
 
461
                form = AddFormInfo(fname, NULL, current_form);
 
462
                if(!form) {
 
463
                  Curl_safefree(fname);
 
464
                  return_value = CURL_FORMADD_MEMORY;
 
465
                }
 
466
                else {
 
467
                  form->value_alloc = TRUE;
 
468
                  current_form = form;
 
469
                  form = NULL;
 
470
                }
 
471
              }
 
472
            }
 
473
            else
 
474
              return_value = CURL_FORMADD_NULL;
 
475
          }
 
476
          else
 
477
            return_value = CURL_FORMADD_OPTION_TWICE;
 
478
        }
 
479
        else {
 
480
          if(filename) {
 
481
            current_form->value = strdup(filename);
 
482
            if(!current_form->value)
 
483
              return_value = CURL_FORMADD_MEMORY;
 
484
            else {
 
485
              current_form->flags |= HTTPPOST_FILENAME;
 
486
              current_form->value_alloc = TRUE;
 
487
            }
 
488
          }
 
489
          else
 
490
            return_value = CURL_FORMADD_NULL;
 
491
        }
 
492
        break;
 
493
      }
 
494
 
 
495
    case CURLFORM_BUFFERPTR:
 
496
      current_form->flags |= HTTPPOST_PTRBUFFER|HTTPPOST_BUFFER;
 
497
      if(current_form->buffer)
 
498
        return_value = CURL_FORMADD_OPTION_TWICE;
 
499
      else {
 
500
        char *buffer =
 
501
          array_state?array_value:va_arg(params, char *);
 
502
        if(buffer) {
 
503
          current_form->buffer = buffer; /* store for the moment */
 
504
          current_form->value = buffer; /* make it non-NULL to be accepted
 
505
                                           as fine */
 
506
        }
 
507
        else
 
508
          return_value = CURL_FORMADD_NULL;
 
509
      }
 
510
      break;
 
511
 
 
512
    case CURLFORM_BUFFERLENGTH:
 
513
      if(current_form->bufferlength)
 
514
        return_value = CURL_FORMADD_OPTION_TWICE;
 
515
      else
 
516
        current_form->bufferlength =
 
517
          array_state?(size_t)array_value:(size_t)va_arg(params, long);
 
518
      break;
 
519
 
 
520
    case CURLFORM_STREAM:
 
521
      current_form->flags |= HTTPPOST_CALLBACK;
 
522
      if(current_form->userp)
 
523
        return_value = CURL_FORMADD_OPTION_TWICE;
 
524
      else {
 
525
        char *userp =
 
526
          array_state?array_value:va_arg(params, char *);
 
527
        if(userp) {
 
528
          current_form->userp = userp;
 
529
          current_form->value = userp; /* this isn't strictly true but we
 
530
                                          derive a value from this later on
 
531
                                          and we need this non-NULL to be
 
532
                                          accepted as a fine form part */
 
533
        }
 
534
        else
 
535
          return_value = CURL_FORMADD_NULL;
 
536
      }
 
537
      break;
 
538
 
 
539
    case CURLFORM_CONTENTTYPE:
 
540
      {
 
541
        const char *contenttype =
 
542
          array_state?array_value:va_arg(params, char *);
 
543
        if(current_form->contenttype) {
 
544
          if(current_form->flags & HTTPPOST_FILENAME) {
 
545
            if(contenttype) {
 
546
              char *type = strdup(contenttype);
 
547
              if(!type)
 
548
                return_value = CURL_FORMADD_MEMORY;
 
549
              else {
 
550
                form = AddFormInfo(NULL, type, current_form);
 
551
                if(!form) {
 
552
                  Curl_safefree(type);
 
553
                  return_value = CURL_FORMADD_MEMORY;
 
554
                }
 
555
                else {
 
556
                  form->contenttype_alloc = TRUE;
 
557
                  current_form = form;
 
558
                  form = NULL;
 
559
                }
 
560
              }
 
561
            }
 
562
            else
 
563
              return_value = CURL_FORMADD_NULL;
 
564
          }
 
565
          else
 
566
            return_value = CURL_FORMADD_OPTION_TWICE;
 
567
        }
 
568
        else {
 
569
          if(contenttype) {
 
570
            current_form->contenttype = strdup(contenttype);
 
571
            if(!current_form->contenttype)
 
572
              return_value = CURL_FORMADD_MEMORY;
 
573
            else
 
574
              current_form->contenttype_alloc = TRUE;
 
575
          }
 
576
          else
 
577
            return_value = CURL_FORMADD_NULL;
 
578
        }
 
579
        break;
 
580
      }
 
581
    case CURLFORM_CONTENTHEADER:
 
582
      {
 
583
        /* this "cast increases required alignment of target type" but
 
584
           we consider it OK anyway */
 
585
        struct curl_slist* list = array_state?
 
586
          (struct curl_slist*)array_value:
 
587
          va_arg(params, struct curl_slist*);
 
588
 
 
589
        if(current_form->contentheader)
 
590
          return_value = CURL_FORMADD_OPTION_TWICE;
 
591
        else
 
592
          current_form->contentheader = list;
 
593
 
 
594
        break;
 
595
      }
 
596
    case CURLFORM_FILENAME:
 
597
    case CURLFORM_BUFFER:
 
598
      {
 
599
        const char *filename = array_state?array_value:
 
600
          va_arg(params, char *);
 
601
        if(current_form->showfilename)
 
602
          return_value = CURL_FORMADD_OPTION_TWICE;
 
603
        else {
 
604
          current_form->showfilename = strdup(filename);
 
605
          if(!current_form->showfilename)
 
606
            return_value = CURL_FORMADD_MEMORY;
 
607
          else
 
608
            current_form->showfilename_alloc = TRUE;
 
609
        }
 
610
        break;
 
611
      }
 
612
    default:
 
613
      return_value = CURL_FORMADD_UNKNOWN_OPTION;
 
614
      break;
 
615
    }
 
616
  }
 
617
 
 
618
  if(CURL_FORMADD_OK != return_value) {
 
619
    /* On error, free allocated fields for all nodes of the FormInfo linked
 
620
       list without deallocating nodes. List nodes are deallocated later on */
 
621
    FormInfo *ptr;
 
622
    for(ptr = first_form; ptr != NULL; ptr = ptr->more) {
 
623
      if(ptr->name_alloc) {
 
624
        Curl_safefree(ptr->name);
 
625
        ptr->name_alloc = FALSE;
 
626
      }
 
627
      if(ptr->value_alloc) {
 
628
        Curl_safefree(ptr->value);
 
629
        ptr->value_alloc = FALSE;
 
630
      }
 
631
      if(ptr->contenttype_alloc) {
 
632
        Curl_safefree(ptr->contenttype);
 
633
        ptr->contenttype_alloc = FALSE;
 
634
      }
 
635
      if(ptr->showfilename_alloc) {
 
636
        Curl_safefree(ptr->showfilename);
 
637
        ptr->showfilename_alloc = FALSE;
 
638
      }
 
639
    }
 
640
  }
 
641
 
 
642
  if(CURL_FORMADD_OK == return_value) {
 
643
    /* go through the list, check for completeness and if everything is
 
644
     * alright add the HttpPost item otherwise set return_value accordingly */
 
645
 
 
646
    post = NULL;
 
647
    for(form = first_form;
 
648
        form != NULL;
 
649
        form = form->more) {
 
650
      if(((!form->name || !form->value) && !post) ||
 
651
         ( (form->contentslength) &&
 
652
           (form->flags & HTTPPOST_FILENAME) ) ||
 
653
         ( (form->flags & HTTPPOST_FILENAME) &&
 
654
           (form->flags & HTTPPOST_PTRCONTENTS) ) ||
 
655
 
 
656
         ( (!form->buffer) &&
 
657
           (form->flags & HTTPPOST_BUFFER) &&
 
658
           (form->flags & HTTPPOST_PTRBUFFER) ) ||
 
659
 
 
660
         ( (form->flags & HTTPPOST_READFILE) &&
 
661
           (form->flags & HTTPPOST_PTRCONTENTS) )
 
662
        ) {
 
663
        return_value = CURL_FORMADD_INCOMPLETE;
 
664
        break;
 
665
      }
 
666
      else {
 
667
        if(((form->flags & HTTPPOST_FILENAME) ||
 
668
            (form->flags & HTTPPOST_BUFFER)) &&
 
669
           !form->contenttype ) {
 
670
          char *f = form->flags & HTTPPOST_BUFFER?
 
671
            form->showfilename : form->value;
 
672
 
 
673
          /* our contenttype is missing */
 
674
          form->contenttype = strdup(ContentTypeForFilename(f, prevtype));
 
675
          if(!form->contenttype) {
 
676
            return_value = CURL_FORMADD_MEMORY;
 
677
            break;
 
678
          }
 
679
          form->contenttype_alloc = TRUE;
 
680
        }
 
681
        if(!(form->flags & HTTPPOST_PTRNAME) &&
 
682
           (form == first_form) ) {
 
683
          /* Note that there's small risk that form->name is NULL here if the
 
684
             app passed in a bad combo, so we better check for that first. */
 
685
          if(form->name)
 
686
            /* copy name (without strdup; possibly contains null characters) */
 
687
            form->name = memdup(form->name, form->namelength);
 
688
          if(!form->name) {
 
689
            return_value = CURL_FORMADD_MEMORY;
 
690
            break;
 
691
          }
 
692
          form->name_alloc = TRUE;
 
693
        }
 
694
        if(!(form->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE |
 
695
                            HTTPPOST_PTRCONTENTS | HTTPPOST_PTRBUFFER |
 
696
                            HTTPPOST_CALLBACK)) ) {
 
697
          /* copy value (without strdup; possibly contains null characters) */
 
698
          form->value = memdup(form->value, form->contentslength);
 
699
          if(!form->value) {
 
700
            return_value = CURL_FORMADD_MEMORY;
 
701
            break;
 
702
          }
 
703
          form->value_alloc = TRUE;
 
704
        }
 
705
        post = AddHttpPost(form->name, form->namelength,
 
706
                           form->value, form->contentslength,
 
707
                           form->buffer, form->bufferlength,
 
708
                           form->contenttype, form->flags,
 
709
                           form->contentheader, form->showfilename,
 
710
                           form->userp,
 
711
                           post, httppost,
 
712
                           last_post);
 
713
 
 
714
        if(!post) {
 
715
          return_value = CURL_FORMADD_MEMORY;
 
716
          break;
 
717
        }
 
718
 
 
719
        if(form->contenttype)
 
720
          prevtype = form->contenttype;
 
721
      }
 
722
    }
 
723
    if(CURL_FORMADD_OK != return_value) {
 
724
      /* On error, free allocated fields for nodes of the FormInfo linked
 
725
         list which are not already owned by the httppost linked list
 
726
         without deallocating nodes. List nodes are deallocated later on */
 
727
      FormInfo *ptr;
 
728
      for(ptr = form; ptr != NULL; ptr = ptr->more) {
 
729
        if(ptr->name_alloc) {
 
730
          Curl_safefree(ptr->name);
 
731
          ptr->name_alloc = FALSE;
 
732
        }
 
733
        if(ptr->value_alloc) {
 
734
          Curl_safefree(ptr->value);
 
735
          ptr->value_alloc = FALSE;
 
736
        }
 
737
        if(ptr->contenttype_alloc) {
 
738
          Curl_safefree(ptr->contenttype);
 
739
          ptr->contenttype_alloc = FALSE;
 
740
        }
 
741
        if(ptr->showfilename_alloc) {
 
742
          Curl_safefree(ptr->showfilename);
 
743
          ptr->showfilename_alloc = FALSE;
 
744
        }
 
745
      }
 
746
    }
 
747
  }
 
748
 
 
749
  /* Always deallocate FormInfo linked list nodes without touching node
 
750
     fields given that these have either been deallocated or are owned
 
751
     now by the httppost linked list */
 
752
  while(first_form) {
 
753
    FormInfo *ptr = first_form->more;
 
754
    Curl_safefree(first_form);
 
755
    first_form = ptr;
 
756
  }
 
757
 
 
758
  return return_value;
 
759
}
 
760
 
 
761
/*
 
762
 * curl_formadd() is a public API to add a section to the multipart formpost.
 
763
 *
 
764
 * @unittest: 1308
 
765
 */
 
766
 
 
767
CURLFORMcode curl_formadd(struct curl_httppost **httppost,
 
768
                          struct curl_httppost **last_post,
 
769
                          ...)
 
770
{
 
771
  va_list arg;
 
772
  CURLFORMcode result;
 
773
  va_start(arg, last_post);
 
774
  result = FormAdd(httppost, last_post, arg);
 
775
  va_end(arg);
 
776
  return result;
 
777
}
 
778
 
 
779
#ifdef __VMS
 
780
#include <fabdef.h>
 
781
/*
 
782
 * get_vms_file_size does what it takes to get the real size of the file
 
783
 *
 
784
 * For fixed files, find out the size of the EOF block and adjust.
 
785
 *
 
786
 * For all others, have to read the entire file in, discarding the contents.
 
787
 * Most posted text files will be small, and binary files like zlib archives
 
788
 * and CD/DVD images should be either a STREAM_LF format or a fixed format.
 
789
 *
 
790
 */
 
791
curl_off_t VmsRealFileSize(const char * name,
 
792
                           const struct_stat * stat_buf)
 
793
{
 
794
  char buffer[8192];
 
795
  curl_off_t count;
 
796
  int ret_stat;
 
797
  FILE * file;
 
798
 
 
799
  file = fopen(name, "r");
 
800
  if(file == NULL)
 
801
    return 0;
 
802
 
 
803
  count = 0;
 
804
  ret_stat = 1;
 
805
  while(ret_stat > 0) {
 
806
    ret_stat = fread(buffer, 1, sizeof(buffer), file);
 
807
    if(ret_stat != 0)
 
808
      count += ret_stat;
 
809
  }
 
810
  fclose(file);
 
811
 
 
812
  return count;
 
813
}
 
814
 
 
815
/*
 
816
 *
 
817
 *  VmsSpecialSize checks to see if the stat st_size can be trusted and
 
818
 *  if not to call a routine to get the correct size.
 
819
 *
 
820
 */
 
821
static curl_off_t VmsSpecialSize(const char * name,
 
822
                                 const struct_stat * stat_buf)
 
823
{
 
824
  switch(stat_buf->st_fab_rfm) {
 
825
  case FAB$C_VAR:
 
826
  case FAB$C_VFC:
 
827
    return VmsRealFileSize(name, stat_buf);
 
828
    break;
 
829
  default:
 
830
    return stat_buf->st_size;
 
831
  }
 
832
}
 
833
 
 
834
#endif
 
835
 
 
836
#ifndef __VMS
 
837
#define filesize(name, stat_data) (stat_data.st_size)
 
838
#else
 
839
    /* Getting the expected file size needs help on VMS */
 
840
#define filesize(name, stat_data) VmsSpecialSize(name, &stat_data)
 
841
#endif
 
842
 
 
843
/*
 
844
 * AddFormData() adds a chunk of data to the FormData linked list.
 
845
 *
 
846
 * size is incremented by the chunk length, unless it is NULL
 
847
 */
 
848
static CURLcode AddFormData(struct FormData **formp,
 
849
                            enum formtype type,
 
850
                            const void *line,
 
851
                            size_t length,
 
852
                            curl_off_t *size)
 
853
{
 
854
  struct FormData *newform = malloc(sizeof(struct FormData));
 
855
  if(!newform)
 
856
    return CURLE_OUT_OF_MEMORY;
 
857
  newform->next = NULL;
 
858
 
 
859
  if(type <= FORM_CONTENT) {
 
860
    /* we make it easier for plain strings: */
 
861
    if(!length)
 
862
      length = strlen((char *)line);
 
863
 
 
864
    newform->line = malloc(length+1);
 
865
    if(!newform->line) {
 
866
      free(newform);
 
867
      return CURLE_OUT_OF_MEMORY;
 
868
    }
 
869
    memcpy(newform->line, line, length);
 
870
    newform->length = length;
 
871
    newform->line[length]=0; /* zero terminate for easier debugging */
 
872
  }
 
873
  else
 
874
    /* For callbacks and files we don't have any actual data so we just keep a
 
875
       pointer to whatever this points to */
 
876
    newform->line = (char *)line;
 
877
 
 
878
  newform->type = type;
 
879
 
 
880
  if(*formp) {
 
881
    (*formp)->next = newform;
 
882
    *formp = newform;
 
883
  }
 
884
  else
 
885
    *formp = newform;
 
886
 
 
887
  if(size) {
 
888
    if(type != FORM_FILE)
 
889
      /* for static content as well as callback data we add the size given
 
890
         as input argument */
 
891
      *size += length;
 
892
    else {
 
893
      /* Since this is a file to be uploaded here, add the size of the actual
 
894
         file */
 
895
      if(!strequal("-", newform->line)) {
 
896
        struct_stat file;
 
897
        if(!stat(newform->line, &file) && !S_ISDIR(file.st_mode))
 
898
          *size += filesize(newform->line, file);
 
899
        else
 
900
          return CURLE_BAD_FUNCTION_ARGUMENT;
 
901
      }
 
902
    }
 
903
  }
 
904
  return CURLE_OK;
 
905
}
 
906
 
 
907
/*
 
908
 * AddFormDataf() adds printf()-style formatted data to the formdata chain.
 
909
 */
 
910
 
 
911
static CURLcode AddFormDataf(struct FormData **formp,
 
912
                             curl_off_t *size,
 
913
                             const char *fmt, ...)
 
914
{
 
915
  char s[4096];
 
916
  va_list ap;
 
917
  va_start(ap, fmt);
 
918
  vsnprintf(s, sizeof(s), fmt, ap);
 
919
  va_end(ap);
 
920
 
 
921
  return AddFormData(formp, FORM_DATA, s, 0, size);
 
922
}
 
923
 
 
924
/*
 
925
 * Curl_formclean() is used from http.c, this cleans a built FormData linked
 
926
 * list
 
927
 */
 
928
void Curl_formclean(struct FormData **form_ptr)
 
929
{
 
930
  struct FormData *next, *form;
 
931
 
 
932
  form = *form_ptr;
 
933
  if(!form)
 
934
    return;
 
935
 
 
936
  do {
 
937
    next=form->next;  /* the following form line */
 
938
    if(form->type <= FORM_CONTENT)
 
939
      free(form->line); /* free the line */
 
940
    free(form);       /* free the struct */
 
941
 
 
942
  } while((form = next) != NULL); /* continue */
 
943
 
 
944
  *form_ptr = NULL;
 
945
}
 
946
 
 
947
/*
 
948
 * curl_formget()
 
949
 * Serialize a curl_httppost struct.
 
950
 * Returns 0 on success.
 
951
 *
 
952
 * @unittest: 1308
 
953
 */
 
954
int curl_formget(struct curl_httppost *form, void *arg,
 
955
                 curl_formget_callback append)
 
956
{
 
957
  CURLcode rc;
 
958
  curl_off_t size;
 
959
  struct FormData *data, *ptr;
 
960
 
 
961
  rc = Curl_getformdata(NULL, &data, form, NULL, &size);
 
962
  if(rc != CURLE_OK)
 
963
    return (int)rc;
 
964
 
 
965
  for(ptr = data; ptr; ptr = ptr->next) {
 
966
    if((ptr->type == FORM_FILE) || (ptr->type == FORM_CALLBACK)) {
 
967
      char buffer[8192];
 
968
      size_t nread;
 
969
      struct Form temp;
 
970
 
 
971
      Curl_FormInit(&temp, ptr);
 
972
 
 
973
      do {
 
974
        nread = readfromfile(&temp, buffer, sizeof(buffer));
 
975
        if((nread == (size_t) -1) ||
 
976
           (nread > sizeof(buffer)) ||
 
977
           (nread != append(arg, buffer, nread))) {
 
978
          if(temp.fp)
 
979
            fclose(temp.fp);
 
980
          Curl_formclean(&data);
 
981
          return -1;
 
982
        }
 
983
      } while(nread);
 
984
    }
 
985
    else {
 
986
      if(ptr->length != append(arg, ptr->line, ptr->length)) {
 
987
        Curl_formclean(&data);
 
988
        return -1;
 
989
      }
 
990
    }
 
991
  }
 
992
  Curl_formclean(&data);
 
993
  return 0;
 
994
}
 
995
 
 
996
/*
 
997
 * curl_formfree() is an external function to free up a whole form post
 
998
 * chain
 
999
 */
 
1000
void curl_formfree(struct curl_httppost *form)
 
1001
{
 
1002
  struct curl_httppost *next;
 
1003
 
 
1004
  if(!form)
 
1005
    /* no form to free, just get out of this */
 
1006
    return;
 
1007
 
 
1008
  do {
 
1009
    next=form->next;  /* the following form line */
 
1010
 
 
1011
    /* recurse to sub-contents */
 
1012
    if(form->more)
 
1013
      curl_formfree(form->more);
 
1014
 
 
1015
    if(!(form->flags & HTTPPOST_PTRNAME) && form->name)
 
1016
      free(form->name); /* free the name */
 
1017
    if(!(form->flags &
 
1018
         (HTTPPOST_PTRCONTENTS|HTTPPOST_BUFFER|HTTPPOST_CALLBACK)) &&
 
1019
       form->contents)
 
1020
      free(form->contents); /* free the contents */
 
1021
    if(form->contenttype)
 
1022
      free(form->contenttype); /* free the content type */
 
1023
    if(form->showfilename)
 
1024
      free(form->showfilename); /* free the faked file name */
 
1025
    free(form);       /* free the struct */
 
1026
 
 
1027
  } while((form = next) != NULL); /* continue */
 
1028
}
 
1029
 
 
1030
#ifndef HAVE_BASENAME
 
1031
/*
 
1032
  (Quote from The Open Group Base Specifications Issue 6 IEEE Std 1003.1, 2004
 
1033
  Edition)
 
1034
 
 
1035
  The basename() function shall take the pathname pointed to by path and
 
1036
  return a pointer to the final component of the pathname, deleting any
 
1037
  trailing '/' characters.
 
1038
 
 
1039
  If the string pointed to by path consists entirely of the '/' character,
 
1040
  basename() shall return a pointer to the string "/". If the string pointed
 
1041
  to by path is exactly "//", it is implementation-defined whether '/' or "//"
 
1042
  is returned.
 
1043
 
 
1044
  If path is a null pointer or points to an empty string, basename() shall
 
1045
  return a pointer to the string ".".
 
1046
 
 
1047
  The basename() function may modify the string pointed to by path, and may
 
1048
  return a pointer to static storage that may then be overwritten by a
 
1049
  subsequent call to basename().
 
1050
 
 
1051
  The basename() function need not be reentrant. A function that is not
 
1052
  required to be reentrant is not required to be thread-safe.
 
1053
 
 
1054
*/
 
1055
static char *Curl_basename(char *path)
 
1056
{
 
1057
  /* Ignore all the details above for now and make a quick and simple
 
1058
     implementaion here */
 
1059
  char *s1;
 
1060
  char *s2;
 
1061
 
 
1062
  s1=strrchr(path, '/');
 
1063
  s2=strrchr(path, '\\');
 
1064
 
 
1065
  if(s1 && s2) {
 
1066
    path = (s1 > s2? s1 : s2)+1;
 
1067
  }
 
1068
  else if(s1)
 
1069
    path = s1 + 1;
 
1070
  else if(s2)
 
1071
    path = s2 + 1;
 
1072
 
 
1073
  return path;
 
1074
}
 
1075
#endif
 
1076
 
 
1077
static char *strippath(const char *fullfile)
 
1078
{
 
1079
  char *filename;
 
1080
  char *base;
 
1081
  filename = strdup(fullfile); /* duplicate since basename() may ruin the
 
1082
                                  buffer it works on */
 
1083
  if(!filename)
 
1084
    return NULL;
 
1085
  base = strdup(basename(filename));
 
1086
 
 
1087
  free(filename); /* free temporary buffer */
 
1088
 
 
1089
  return base; /* returns an allocated string or NULL ! */
 
1090
}
 
1091
 
 
1092
static CURLcode formdata_add_filename(const struct curl_httppost *file,
 
1093
                                      struct FormData **form,
 
1094
                                      curl_off_t *size)
 
1095
{
 
1096
  CURLcode result = CURLE_OK;
 
1097
  char *filename = file->showfilename;
 
1098
  char *filebasename = NULL;
 
1099
  char *filename_escaped = NULL;
 
1100
 
 
1101
  if(!filename) {
 
1102
    filebasename = strippath(file->contents);
 
1103
    if(!filebasename)
 
1104
      return CURLE_OUT_OF_MEMORY;
 
1105
    filename = filebasename;
 
1106
  }
 
1107
 
 
1108
  if(strchr(filename, '\\') || strchr(filename, '"')) {
 
1109
    char *p0, *p1;
 
1110
 
 
1111
    /* filename need be escaped */
 
1112
    filename_escaped = malloc(strlen(filename)*2+1);
 
1113
    if(!filename_escaped)
 
1114
      return CURLE_OUT_OF_MEMORY;
 
1115
    p0 = filename_escaped;
 
1116
    p1 = filename;
 
1117
    while(*p1) {
 
1118
      if(*p1 == '\\' || *p1 == '"')
 
1119
        *p0++ = '\\';
 
1120
      *p0++ = *p1++;
 
1121
    }
 
1122
    *p0 = '\0';
 
1123
    filename = filename_escaped;
 
1124
  }
 
1125
  result = AddFormDataf(form, size,
 
1126
                        "; filename=\"%s\"",
 
1127
                        filename);
 
1128
  Curl_safefree(filename_escaped);
 
1129
  Curl_safefree(filebasename);
 
1130
  return result;
 
1131
}
 
1132
 
 
1133
/*
 
1134
 * Curl_getformdata() converts a linked list of "meta data" into a complete
 
1135
 * (possibly huge) multipart formdata. The input list is in 'post', while the
 
1136
 * output resulting linked lists gets stored in '*finalform'. *sizep will get
 
1137
 * the total size of the whole POST.
 
1138
 * A multipart/form_data content-type is built, unless a custom content-type
 
1139
 * is passed in 'custom_content_type'.
 
1140
 *
 
1141
 * This function will not do a failf() for the potential memory failures but
 
1142
 * should for all other errors it spots. Just note that this function MAY get
 
1143
 * a NULL pointer in the 'data' argument.
 
1144
 */
 
1145
 
 
1146
CURLcode Curl_getformdata(struct SessionHandle *data,
 
1147
                          struct FormData **finalform,
 
1148
                          struct curl_httppost *post,
 
1149
                          const char *custom_content_type,
 
1150
                          curl_off_t *sizep)
 
1151
{
 
1152
  struct FormData *form = NULL;
 
1153
  struct FormData *firstform;
 
1154
  struct curl_httppost *file;
 
1155
  CURLcode result = CURLE_OK;
 
1156
 
 
1157
  curl_off_t size = 0; /* support potentially ENORMOUS formposts */
 
1158
  char *boundary;
 
1159
  char *fileboundary = NULL;
 
1160
  struct curl_slist* curList;
 
1161
 
 
1162
  *finalform = NULL; /* default form is empty */
 
1163
 
 
1164
  if(!post)
 
1165
    return result; /* no input => no output! */
 
1166
 
 
1167
  boundary = formboundary(data);
 
1168
  if(!boundary)
 
1169
    return CURLE_OUT_OF_MEMORY;
 
1170
 
 
1171
  /* Make the first line of the output */
 
1172
  result = AddFormDataf(&form, NULL,
 
1173
                        "%s; boundary=%s\r\n",
 
1174
                        custom_content_type?custom_content_type:
 
1175
                        "Content-Type: multipart/form-data",
 
1176
                        boundary);
 
1177
 
 
1178
  if(result) {
 
1179
    Curl_safefree(boundary);
 
1180
    return result;
 
1181
  }
 
1182
  /* we DO NOT include that line in the total size of the POST, since it'll be
 
1183
     part of the header! */
 
1184
 
 
1185
  firstform = form;
 
1186
 
 
1187
  do {
 
1188
 
 
1189
    if(size) {
 
1190
      result = AddFormDataf(&form, &size, "\r\n");
 
1191
      if(result)
 
1192
        break;
 
1193
    }
 
1194
 
 
1195
    /* boundary */
 
1196
    result = AddFormDataf(&form, &size, "--%s\r\n", boundary);
 
1197
    if(result)
 
1198
      break;
 
1199
 
 
1200
    /* Maybe later this should be disabled when a custom_content_type is
 
1201
       passed, since Content-Disposition is not meaningful for all multipart
 
1202
       types.
 
1203
    */
 
1204
    result = AddFormDataf(&form, &size,
 
1205
                          "Content-Disposition: form-data; name=\"");
 
1206
    if(result)
 
1207
      break;
 
1208
 
 
1209
    result = AddFormData(&form, FORM_DATA, post->name, post->namelength,
 
1210
                         &size);
 
1211
    if(result)
 
1212
      break;
 
1213
 
 
1214
    result = AddFormDataf(&form, &size, "\"");
 
1215
    if(result)
 
1216
      break;
 
1217
 
 
1218
    if(post->more) {
 
1219
      /* If used, this is a link to more file names, we must then do
 
1220
         the magic to include several files with the same field name */
 
1221
 
 
1222
      Curl_safefree(fileboundary);
 
1223
      fileboundary = formboundary(data);
 
1224
      if(!fileboundary) {
 
1225
        result = CURLE_OUT_OF_MEMORY;
 
1226
        break;
 
1227
      }
 
1228
 
 
1229
      result = AddFormDataf(&form, &size,
 
1230
                            "\r\nContent-Type: multipart/mixed,"
 
1231
                            " boundary=%s\r\n",
 
1232
                            fileboundary);
 
1233
      if(result)
 
1234
        break;
 
1235
    }
 
1236
 
 
1237
    file = post;
 
1238
 
 
1239
    do {
 
1240
 
 
1241
      /* If 'showfilename' is set, that is a faked name passed on to us
 
1242
         to use to in the formpost. If that is not set, the actually used
 
1243
         local file name should be added. */
 
1244
 
 
1245
      if(post->more) {
 
1246
        /* if multiple-file */
 
1247
        result = AddFormDataf(&form, &size,
 
1248
                              "\r\n--%s\r\nContent-Disposition: "
 
1249
                              "attachment",
 
1250
                              fileboundary);
 
1251
        if(result)
 
1252
          break;
 
1253
        result = formdata_add_filename(file, &form, &size);
 
1254
        if(result)
 
1255
          break;
 
1256
      }
 
1257
      else if(post->flags & (HTTPPOST_FILENAME|HTTPPOST_BUFFER|
 
1258
                             HTTPPOST_CALLBACK)) {
 
1259
        /* it should be noted that for the HTTPPOST_FILENAME and
 
1260
           HTTPPOST_CALLBACK cases the ->showfilename struct member is always
 
1261
           assigned at this point */
 
1262
        if(post->showfilename || (post->flags & HTTPPOST_FILENAME)) {
 
1263
          result = formdata_add_filename(post, &form, &size);
 
1264
        }
 
1265
 
 
1266
        if(result)
 
1267
          break;
 
1268
      }
 
1269
 
 
1270
      if(file->contenttype) {
 
1271
        /* we have a specified type */
 
1272
        result = AddFormDataf(&form, &size,
 
1273
                              "\r\nContent-Type: %s",
 
1274
                              file->contenttype);
 
1275
        if(result)
 
1276
          break;
 
1277
      }
 
1278
 
 
1279
      curList = file->contentheader;
 
1280
      while(curList) {
 
1281
        /* Process the additional headers specified for this form */
 
1282
        result = AddFormDataf( &form, &size, "\r\n%s", curList->data );
 
1283
        if(result)
 
1284
          break;
 
1285
        curList = curList->next;
 
1286
      }
 
1287
      if(result)
 
1288
        break;
 
1289
 
 
1290
      result = AddFormDataf(&form, &size, "\r\n\r\n");
 
1291
      if(result)
 
1292
        break;
 
1293
 
 
1294
      if((post->flags & HTTPPOST_FILENAME) ||
 
1295
         (post->flags & HTTPPOST_READFILE)) {
 
1296
        /* we should include the contents from the specified file */
 
1297
        FILE *fileread;
 
1298
 
 
1299
        fileread = strequal("-", file->contents)?
 
1300
          stdin:fopen(file->contents, "rb"); /* binary read for win32  */
 
1301
 
 
1302
        /*
 
1303
         * VMS: This only allows for stream files on VMS.  Stream files are
 
1304
         * OK, as are FIXED & VAR files WITHOUT implied CC For implied CC,
 
1305
         * every record needs to have a \n appended & 1 added to SIZE
 
1306
         */
 
1307
 
 
1308
        if(fileread) {
 
1309
          if(fileread != stdin) {
 
1310
            /* close the file */
 
1311
            fclose(fileread);
 
1312
            /* add the file name only - for later reading from this */
 
1313
            result = AddFormData(&form, FORM_FILE, file->contents, 0, &size);
 
1314
          }
 
1315
          else {
 
1316
            /* When uploading from stdin, we can't know the size of the file,
 
1317
             * thus must read the full file as before. We *could* use chunked
 
1318
             * transfer-encoding, but that only works for HTTP 1.1 and we
 
1319
             * can't be sure we work with such a server.
 
1320
             */
 
1321
            size_t nread;
 
1322
            char buffer[512];
 
1323
            while((nread = fread(buffer, 1, sizeof(buffer), fileread)) != 0) {
 
1324
              result = AddFormData(&form, FORM_CONTENT, buffer, nread, &size);
 
1325
              if(result)
 
1326
                break;
 
1327
            }
 
1328
          }
 
1329
        }
 
1330
        else {
 
1331
          if(data)
 
1332
            failf(data, "couldn't open file \"%s\"", file->contents);
 
1333
          *finalform = NULL;
 
1334
          result = CURLE_READ_ERROR;
 
1335
        }
 
1336
      }
 
1337
      else if(post->flags & HTTPPOST_BUFFER)
 
1338
        /* include contents of buffer */
 
1339
        result = AddFormData(&form, FORM_CONTENT, post->buffer,
 
1340
                             post->bufferlength, &size);
 
1341
      else if(post->flags & HTTPPOST_CALLBACK)
 
1342
        /* the contents should be read with the callback and the size
 
1343
           is set with the contentslength */
 
1344
        result = AddFormData(&form, FORM_CALLBACK, post->userp,
 
1345
                             post->contentslength, &size);
 
1346
      else
 
1347
        /* include the contents we got */
 
1348
        result = AddFormData(&form, FORM_CONTENT, post->contents,
 
1349
                             post->contentslength, &size);
 
1350
 
 
1351
      file = file->more;
 
1352
    } while(file && !result); /* for each specified file for this field */
 
1353
 
 
1354
    if(result)
 
1355
      break;
 
1356
 
 
1357
    if(post->more) {
 
1358
      /* this was a multiple-file inclusion, make a termination file
 
1359
         boundary: */
 
1360
      result = AddFormDataf(&form, &size,
 
1361
                           "\r\n--%s--",
 
1362
                           fileboundary);
 
1363
      if(result)
 
1364
        break;
 
1365
    }
 
1366
 
 
1367
  } while((post = post->next) != NULL); /* for each field */
 
1368
 
 
1369
  /* end-boundary for everything */
 
1370
  if(CURLE_OK == result)
 
1371
    result = AddFormDataf(&form, &size,
 
1372
                          "\r\n--%s--\r\n",
 
1373
                          boundary);
 
1374
 
 
1375
  if(result) {
 
1376
    Curl_formclean(&firstform);
 
1377
    Curl_safefree(fileboundary);
 
1378
    Curl_safefree(boundary);
 
1379
    return result;
 
1380
  }
 
1381
 
 
1382
  *sizep = size;
 
1383
 
 
1384
  Curl_safefree(fileboundary);
 
1385
  Curl_safefree(boundary);
 
1386
 
 
1387
  *finalform = firstform;
 
1388
 
 
1389
  return result;
 
1390
}
 
1391
 
 
1392
/*
 
1393
 * Curl_FormInit() inits the struct 'form' points to with the 'formdata'
 
1394
 * and resets the 'sent' counter.
 
1395
 */
 
1396
int Curl_FormInit(struct Form *form, struct FormData *formdata )
 
1397
{
 
1398
  if(!formdata)
 
1399
    return 1; /* error */
 
1400
 
 
1401
  form->data = formdata;
 
1402
  form->sent = 0;
 
1403
  form->fp = NULL;
 
1404
  form->fread_func = ZERO_NULL;
 
1405
 
 
1406
  return 0;
 
1407
}
 
1408
 
 
1409
#ifndef __VMS
 
1410
# define fopen_read fopen
 
1411
#else
 
1412
  /*
 
1413
   * vmsfopenread
 
1414
   *
 
1415
   * For upload to work as expected on VMS, different optional
 
1416
   * parameters must be added to the fopen command based on
 
1417
   * record format of the file.
 
1418
   *
 
1419
   */
 
1420
# define fopen_read vmsfopenread
 
1421
static FILE * vmsfopenread(const char *file, const char *mode) {
 
1422
  struct_stat statbuf;
 
1423
  int result;
 
1424
 
 
1425
  result = stat(file, &statbuf);
 
1426
 
 
1427
  switch (statbuf.st_fab_rfm) {
 
1428
  case FAB$C_VAR:
 
1429
  case FAB$C_VFC:
 
1430
  case FAB$C_STMCR:
 
1431
    return fopen(file, "r");
 
1432
    break;
 
1433
  default:
 
1434
    return fopen(file, "r", "rfm=stmlf", "ctx=stm");
 
1435
  }
 
1436
}
 
1437
#endif
 
1438
 
 
1439
/*
 
1440
 * readfromfile()
 
1441
 *
 
1442
 * The read callback that this function may use can return a value larger than
 
1443
 * 'size' (which then this function returns) that indicates a problem and it
 
1444
 * must be properly dealt with
 
1445
 */
 
1446
static size_t readfromfile(struct Form *form, char *buffer,
 
1447
                           size_t size)
 
1448
{
 
1449
  size_t nread;
 
1450
  bool callback = (form->data->type == FORM_CALLBACK)?TRUE:FALSE;
 
1451
 
 
1452
  if(callback) {
 
1453
    if(form->fread_func == ZERO_NULL)
 
1454
      return 0;
 
1455
    else
 
1456
      nread = form->fread_func(buffer, 1, size, form->data->line);
 
1457
  }
 
1458
  else {
 
1459
    if(!form->fp) {
 
1460
      /* this file hasn't yet been opened */
 
1461
      form->fp = fopen_read(form->data->line, "rb"); /* b is for binary */
 
1462
      if(!form->fp)
 
1463
        return (size_t)-1; /* failure */
 
1464
    }
 
1465
    nread = fread(buffer, 1, size, form->fp);
 
1466
  }
 
1467
  if(!nread) {
 
1468
    /* this is the last chunk from the file, move on */
 
1469
    if(form->fp) {
 
1470
      fclose(form->fp);
 
1471
      form->fp = NULL;
 
1472
    }
 
1473
    form->data = form->data->next;
 
1474
  }
 
1475
 
 
1476
  return nread;
 
1477
}
 
1478
 
 
1479
/*
 
1480
 * Curl_FormReader() is the fread() emulation function that will be used to
 
1481
 * deliver the formdata to the transfer loop and then sent away to the peer.
 
1482
 */
 
1483
size_t Curl_FormReader(char *buffer,
 
1484
                       size_t size,
 
1485
                       size_t nitems,
 
1486
                       FILE *mydata)
 
1487
{
 
1488
  struct Form *form;
 
1489
  size_t wantedsize;
 
1490
  size_t gotsize = 0;
 
1491
 
 
1492
  form=(struct Form *)mydata;
 
1493
 
 
1494
  wantedsize = size * nitems;
 
1495
 
 
1496
  if(!form->data)
 
1497
    return 0; /* nothing, error, empty */
 
1498
 
 
1499
  if((form->data->type == FORM_FILE) ||
 
1500
     (form->data->type == FORM_CALLBACK)) {
 
1501
    gotsize = readfromfile(form, buffer, wantedsize);
 
1502
 
 
1503
    if(gotsize)
 
1504
      /* If positive or -1, return. If zero, continue! */
 
1505
      return gotsize;
 
1506
  }
 
1507
  do {
 
1508
 
 
1509
    if((form->data->length - form->sent ) > wantedsize - gotsize) {
 
1510
 
 
1511
      memcpy(buffer + gotsize , form->data->line + form->sent,
 
1512
             wantedsize - gotsize);
 
1513
 
 
1514
      form->sent += wantedsize-gotsize;
 
1515
 
 
1516
      return wantedsize;
 
1517
    }
 
1518
 
 
1519
    memcpy(buffer+gotsize,
 
1520
           form->data->line + form->sent,
 
1521
           (form->data->length - form->sent) );
 
1522
    gotsize += form->data->length - form->sent;
 
1523
 
 
1524
    form->sent = 0;
 
1525
 
 
1526
    form->data = form->data->next; /* advance */
 
1527
 
 
1528
  } while(form->data && (form->data->type < FORM_CALLBACK));
 
1529
  /* If we got an empty line and we have more data, we proceed to the next
 
1530
     line immediately to avoid returning zero before we've reached the end. */
 
1531
 
 
1532
  return gotsize;
 
1533
}
 
1534
 
 
1535
/*
 
1536
 * Curl_formpostheader() returns the first line of the formpost, the
 
1537
 * request-header part (which is not part of the request-body like the rest of
 
1538
 * the post).
 
1539
 */
 
1540
char *Curl_formpostheader(void *formp, size_t *len)
 
1541
{
 
1542
  char *header;
 
1543
  struct Form *form=(struct Form *)formp;
 
1544
 
 
1545
  if(!form->data)
 
1546
    return 0; /* nothing, ERROR! */
 
1547
 
 
1548
  header = form->data->line;
 
1549
  *len = form->data->length;
 
1550
 
 
1551
  form->data = form->data->next; /* advance */
 
1552
 
 
1553
  return header;
 
1554
}
 
1555
 
 
1556
/*
 
1557
 * formboundary() creates a suitable boundary string and returns an allocated
 
1558
 * one.
 
1559
 */
 
1560
static char *formboundary(struct SessionHandle *data)
 
1561
{
 
1562
  /* 24 dashes and 16 hexadecimal digits makes 64 bit (18446744073709551615)
 
1563
     combinations */
 
1564
  return aprintf("------------------------%08x%08x",
 
1565
                 Curl_rand(data), Curl_rand(data));
 
1566
}
 
1567
 
 
1568
#else  /* CURL_DISABLE_HTTP */
 
1569
CURLFORMcode curl_formadd(struct curl_httppost **httppost,
 
1570
                          struct curl_httppost **last_post,
 
1571
                          ...)
 
1572
{
 
1573
  (void)httppost;
 
1574
  (void)last_post;
 
1575
  return CURL_FORMADD_DISABLED;
 
1576
}
 
1577
 
 
1578
int curl_formget(struct curl_httppost *form, void *arg,
 
1579
                 curl_formget_callback append)
 
1580
{
 
1581
  (void) form;
 
1582
  (void) arg;
 
1583
  (void) append;
 
1584
  return CURL_FORMADD_DISABLED;
 
1585
}
 
1586
 
 
1587
void curl_formfree(struct curl_httppost *form)
 
1588
{
 
1589
  (void)form;
 
1590
  /* does nothing HTTP is disabled */
 
1591
}
 
1592
 
 
1593
 
 
1594
#endif  /* !defined(CURL_DISABLE_HTTP) */