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

« back to all changes in this revision

Viewing changes to lib/cookie.c

  • Committer: Bazaar Package Importer
  • Author(s): LaMont Jones
  • Date: 2005-03-23 18:41:29 UTC
  • mto: (3.1.1 lenny) (1.2.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: james.westby@ubuntu.com-20050323184129-9hgq7luenq51umpu
Tags: upstream-7.12.3
ImportĀ upstreamĀ versionĀ 7.12.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/***************************************************************************
2
 
 *                                  _   _ ____  _     
3
 
 *  Project                     ___| | | |  _ \| |    
4
 
 *                             / __| | | | |_) | |    
5
 
 *                            | (__| |_| |  _ <| |___ 
 
2
 *                                  _   _ ____  _
 
3
 *  Project                     ___| | | |  _ \| |
 
4
 *                             / __| | | | |_) | |
 
5
 *                            | (__| |_| |  _ <| |___
6
6
 *                             \___|\___/|_| \_\_____|
7
7
 *
8
8
 * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
10
10
 * This software is licensed as described in the file COPYING, which
11
11
 * you should have received as part of this distribution. The terms
12
12
 * are also available at http://curl.haxx.se/docs/copyright.html.
13
 
 * 
 
13
 *
14
14
 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15
15
 * copies of the Software, and permit persons to whom the Software is
16
16
 * furnished to do so, under the terms of the COPYING file.
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: cookie.c,v 1.52 2004/03/10 09:41:37 bagder Exp $
 
21
 * $Id: cookie.c,v 1.65 2004/12/05 23:59:32 bagder Exp $
22
22
 ***************************************************************************/
23
23
 
24
24
/***
28
28
============================
29
29
 
30
30
struct CookieInfo *cookie_init(char *file);
31
 
        
32
 
        Inits a cookie struct to store data in a local file. This is always
33
 
        called before any cookies are set.
 
31
 
 
32
        Inits a cookie struct to store data in a local file. This is always
 
33
        called before any cookies are set.
34
34
 
35
35
int cookies_set(struct CookieInfo *cookie, char *cookie_line);
36
36
 
37
 
        The 'cookie_line' parameter is a full "Set-cookie:" line as
38
 
        received from a server.
39
 
 
40
 
        The function need to replace previously stored lines that this new
41
 
        line superceeds.
42
 
 
43
 
        It may remove lines that are expired.
44
 
 
45
 
        It should return an indication of success/error.
 
37
        The 'cookie_line' parameter is a full "Set-cookie:" line as
 
38
        received from a server.
 
39
 
 
40
        The function need to replace previously stored lines that this new
 
41
        line superceeds.
 
42
 
 
43
        It may remove lines that are expired.
 
44
 
 
45
        It should return an indication of success/error.
46
46
 
47
47
 
48
48
SENDING COOKIE INFORMATION
51
51
struct Cookies *cookie_getlist(struct CookieInfo *cookie,
52
52
                               char *host, char *path, bool secure);
53
53
 
54
 
        For a given host and path, return a linked list of cookies that
55
 
        the client should send to the server if used now. The secure
56
 
        boolean informs the cookie if a secure connection is achieved or
57
 
        not.
58
 
 
59
 
        It shall only return cookies that haven't expired.
60
 
 
61
 
    
 
54
        For a given host and path, return a linked list of cookies that
 
55
        the client should send to the server if used now. The secure
 
56
        boolean informs the cookie if a secure connection is achieved or
 
57
        not.
 
58
 
 
59
        It shall only return cookies that haven't expired.
 
60
 
 
61
 
62
62
Example set of cookies:
63
 
    
 
63
 
64
64
    Set-cookie: PRODUCTINFO=webxpress; domain=.fidelity.com; path=/; secure
65
65
    Set-cookie: PERSONALIZE=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
66
66
    domain=.fidelity.com; path=/ftgw; secure
80
80
 
81
81
#include "setup.h"
82
82
 
83
 
#ifndef CURL_DISABLE_HTTP
 
83
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
84
84
 
85
85
#include <stdlib.h>
86
86
#include <string.h>
87
 
#include <ctype.h>
88
87
 
89
88
#include "urldata.h"
90
89
#include "cookie.h"
91
 
#include "getdate.h"
92
90
#include "strequal.h"
93
91
#include "strtok.h"
94
92
#include "sendf.h"
 
93
#include "memory.h"
95
94
 
96
95
/* The last #include file should be: */
97
96
#ifdef CURLDEBUG
98
97
#include "memdebug.h"
99
98
#endif
100
99
 
101
 
static void
102
 
free_cookiemess(struct Cookie *co)
 
100
#define my_isspace(x) ((x == ' ') || (x == '\t'))
 
101
 
 
102
static void freecookie(struct Cookie *co)
103
103
{
 
104
  if(co->expirestr)
 
105
    free(co->expirestr);
104
106
  if(co->domain)
105
107
    free(co->domain);
106
108
  if(co->path)
109
111
    free(co->name);
110
112
  if(co->value)
111
113
    free(co->value);
 
114
  if(co->maxage)
 
115
    free(co->maxage);
112
116
 
113
117
  free(co);
114
118
}
137
141
                /* The 'data' pointer here may be NULL at times, and thus
138
142
                   must only be used very carefully for things that can deal
139
143
                   with data being NULL. Such as infof() and similar */
140
 
                
 
144
 
141
145
                struct CookieInfo *c,
142
146
                bool httpheader, /* TRUE if HTTP header-style line */
143
147
                char *lineptr,   /* first character of the line */
147
151
                                    unless set */
148
152
{
149
153
  struct Cookie *clist;
150
 
  char what[MAX_COOKIE_LINE];
 
154
  char *what;
151
155
  char name[MAX_NAME];
152
156
  char *ptr;
153
157
  char *semiptr;
165
169
  if(httpheader) {
166
170
    /* This line was read off a HTTP-header */
167
171
    char *sep;
 
172
 
 
173
    what = malloc(MAX_COOKIE_LINE);
 
174
    if(!what) {
 
175
      free(co);
 
176
      return NULL;
 
177
    }
 
178
 
168
179
    semiptr=strchr(lineptr, ';'); /* first, find a semicolon */
169
180
 
170
 
    while(*lineptr && isspace((int)*lineptr))
 
181
    while(*lineptr && my_isspace(*lineptr))
171
182
      lineptr++;
172
183
 
173
184
    ptr = lineptr;
190
201
 
191
202
          /* Strip off trailing whitespace from the 'what' */
192
203
          size_t len=strlen(what);
193
 
          while(len && isspace((int)what[len-1])) {
 
204
          while(len && my_isspace(what[len-1])) {
194
205
            what[len-1]=0;
195
206
            len--;
196
207
          }
197
208
 
198
209
          /* Skip leading whitespace from the 'what' */
199
210
          whatptr=what;
200
 
          while(isspace((int)*whatptr)) {
 
211
          while(my_isspace(*whatptr)) {
201
212
            whatptr++;
202
213
          }
203
214
 
204
215
          if(strequal("path", name)) {
205
216
            co->path=strdup(whatptr);
 
217
            if(!co->path) {
 
218
              badcookie = TRUE; /* out of memory bad */
 
219
              break;
 
220
            }
206
221
          }
207
222
          else if(strequal("domain", name)) {
208
223
            /* note that this name may or may not have a preceeding dot, but
210
225
 
211
226
            const char *domptr=whatptr;
212
227
            int dotcount=1;
213
 
            unsigned int i;
214
 
 
215
 
            static const char *seventhree[]= {
216
 
              "com", "edu", "net", "org", "gov", "mil", "int"
217
 
            };
218
 
 
219
 
            /* Count the dots, we need to make sure that there are THREE dots
220
 
               in the normal domains, or TWO in the seventhree-domains. */
 
228
 
 
229
            /* Count the dots, we need to make sure that there are enough
 
230
               of them. */
221
231
 
222
232
            if('.' == whatptr[0])
223
233
              /* don't count the initial dot, assume it */
231
241
              }
232
242
            } while(domptr);
233
243
 
234
 
            for(i=0;
235
 
                i<sizeof(seventhree)/sizeof(seventhree[0]); i++) {
236
 
              if(tailmatch(seventhree[i], whatptr)) {
237
 
                dotcount++; /* we allow one dot less for these */
238
 
                break;
239
 
              }
240
 
            }
241
244
            /* The original Netscape cookie spec defined that this domain name
242
245
               MUST have three dots (or two if one of the seven holy TLDs),
243
246
               but it seems that these kinds of cookies are in use "out there"
244
247
               so we cannot be that strict. I've therefore lowered the check
245
248
               to not allow less than two dots. */
246
 
            
 
249
 
247
250
            if(dotcount < 2) {
248
251
              /* Received and skipped a cookie with a domain using too few
249
252
                 dots. */
250
253
              badcookie=TRUE; /* mark this as a bad cookie */
251
 
              infof(data, "skipped cookie with illegal dotcount domain: %s",
 
254
              infof(data, "skipped cookie with illegal dotcount domain: %s\n",
252
255
                    whatptr);
253
256
            }
254
257
            else {
255
258
              /* Now, we make sure that our host is within the given domain,
256
259
                 or the given domain is not valid and thus cannot be set. */
257
260
 
 
261
              if('.' == whatptr[0])
 
262
                whatptr++; /* ignore preceeding dot */
 
263
 
258
264
              if(!domain || tailmatch(whatptr, domain)) {
259
265
                const char *tailptr=whatptr;
260
266
                if(tailptr[0] == '.')
261
267
                  tailptr++;
262
 
                co->domain=strdup(tailptr); /* don't prefix w/dots internally */
 
268
                co->domain=strdup(tailptr); /* don't prefix w/dots
 
269
                                               internally */
 
270
                if(!co->domain) {
 
271
                  badcookie = TRUE;
 
272
                  break;
 
273
                }
263
274
                co->tailmatch=TRUE; /* we always do that if the domain name was
264
275
                                       given */
265
276
              }
268
279
                   is not a domain to which the current host belongs. Mark as
269
280
                   bad. */
270
281
                badcookie=TRUE;
271
 
                infof(data, "skipped cookie with bad tailmatch domain: %s",
 
282
                infof(data, "skipped cookie with bad tailmatch domain: %s\n",
272
283
                      whatptr);
273
284
              }
274
285
            }
275
286
          }
276
287
          else if(strequal("version", name)) {
277
288
            co->version=strdup(whatptr);
 
289
            if(!co->version) {
 
290
              badcookie = TRUE;
 
291
              break;
 
292
            }
278
293
          }
279
294
          else if(strequal("max-age", name)) {
280
295
            /* Defined in RFC2109:
287
302
 
288
303
             */
289
304
            co->maxage = strdup(whatptr);
 
305
            if(!co->maxage) {
 
306
              badcookie = TRUE;
 
307
              break;
 
308
            }
290
309
            co->expires =
291
310
              atoi((*co->maxage=='\"')?&co->maxage[1]:&co->maxage[0]) + now;
292
311
          }
293
312
          else if(strequal("expires", name)) {
294
313
            co->expirestr=strdup(whatptr);
 
314
            if(!co->expirestr) {
 
315
              badcookie = TRUE;
 
316
              break;
 
317
            }
295
318
            co->expires = curl_getdate(what, &now);
296
319
          }
297
320
          else if(!co->name) {
298
321
            co->name = strdup(name);
299
322
            co->value = strdup(whatptr);
 
323
            if(!co->name || !co->value) {
 
324
              badcookie = TRUE;
 
325
              break;
 
326
            }
300
327
          }
301
328
          /*
302
329
            else this is the second (or more) name we don't know
323
350
      }
324
351
 
325
352
      ptr=semiptr+1;
326
 
      while(ptr && *ptr && isspace((int)*ptr))
 
353
      while(ptr && *ptr && my_isspace(*ptr))
327
354
        ptr++;
328
355
      semiptr=strchr(ptr, ';'); /* now, find the next semicolon */
329
356
 
333
360
        semiptr=strchr(ptr, '\0');
334
361
    } while(semiptr);
335
362
 
336
 
    if(badcookie || (NULL == co->name)) {
337
 
      /* we didn't get a cookie name or a bad one,
338
 
         this is an illegal line, bail out */
339
 
      if(co->expirestr)
340
 
        free(co->expirestr);
341
 
      if(co->domain)
342
 
        free(co->domain);
343
 
      if(co->path)
344
 
        free(co->path);
345
 
      if(co->name)
346
 
        free(co->name);
347
 
      if(co->value)
348
 
        free(co->value);
349
 
      free(co);
350
 
      return NULL;
 
363
    if(!badcookie && !co->domain) {
 
364
      if(domain) {
 
365
        /* no domain was given in the header line, set the default */
 
366
        co->domain=strdup(domain);
 
367
        if(!co->domain)
 
368
          badcookie = TRUE;
 
369
      }
351
370
    }
352
371
 
353
 
    if(NULL == co->domain)
354
 
      /* no domain was given in the header line, set the default now */
355
 
      co->domain=domain?strdup(domain):NULL;
356
 
    if((NULL == co->path) && path) {
357
 
      /* no path was given in the header line, set the default now */
 
372
    if(!badcookie && !co->path && path) {
 
373
      /* no path was given in the header line, set the default  */
358
374
      char *endslash = strrchr(path, '/');
359
375
      if(endslash) {
360
376
        size_t pathlen = endslash-path+1; /* include the ending slash */
363
379
          memcpy(co->path, path, pathlen);
364
380
          co->path[pathlen]=0; /* zero terminate */
365
381
        }
 
382
        else
 
383
          badcookie = TRUE;
366
384
      }
367
385
    }
 
386
 
 
387
    free(what);
 
388
 
 
389
    if(badcookie || !co->name) {
 
390
      /* we didn't get a cookie name or a bad one,
 
391
         this is an illegal line, bail out */
 
392
      freecookie(co);
 
393
      return NULL;
 
394
    }
 
395
 
368
396
  }
369
397
  else {
370
398
    /* This line is NOT a HTTP header style line, we do offer support for
386
414
    if(ptr)
387
415
      *ptr=0; /* clear it */
388
416
 
389
 
    firstptr=strtok_r(lineptr, "\t", &tok_buf); /* first tokenize it on the TAB */
 
417
    firstptr=strtok_r(lineptr, "\t", &tok_buf); /* tokenize it on the TAB */
390
418
 
391
419
    /* Here's a quick check to eliminate normal HTTP-headers from this */
392
420
    if(!firstptr || strchr(firstptr, ':')) {
396
424
 
397
425
    /* Now loop through the fields and init the struct we already have
398
426
       allocated */
399
 
    for(ptr=firstptr, fields=0; ptr;
 
427
    for(ptr=firstptr, fields=0; ptr && !badcookie;
400
428
        ptr=strtok_r(NULL, "\t", &tok_buf), fields++) {
401
429
      switch(fields) {
402
430
      case 0:
403
431
        if(ptr[0]=='.') /* skip preceeding dots */
404
432
          ptr++;
405
433
        co->domain = strdup(ptr);
 
434
        if(!co->domain)
 
435
          badcookie = TRUE;
406
436
        break;
407
437
      case 1:
408
438
        /* This field got its explanation on the 23rd of May 2001 by
424
454
        if (strcmp("TRUE", ptr) && strcmp("FALSE", ptr)) {
425
455
          /* only if the path doesn't look like a boolean option! */
426
456
          co->path = strdup(ptr);
 
457
          if(!co->path)
 
458
            badcookie = TRUE;
427
459
          break;
428
460
        }
429
461
        /* this doesn't look like a path, make one up! */
430
462
        co->path = strdup("/");
 
463
        if(!co->path)
 
464
          badcookie = TRUE;
431
465
        fields++; /* add a field and fall down to secure */
432
466
        /* FALLTHROUGH */
433
467
      case 3:
438
472
        break;
439
473
      case 5:
440
474
        co->name = strdup(ptr);
 
475
        if(!co->name)
 
476
          badcookie = TRUE;
441
477
        break;
442
478
      case 6:
443
479
        co->value = strdup(ptr);
 
480
        if(!co->value)
 
481
          badcookie = TRUE;
444
482
        break;
445
483
      }
446
484
    }
447
 
 
448
485
    if(6 == fields) {
449
486
      /* we got a cookie with blank contents, fix it */
450
487
      co->value = strdup("");
 
488
      if(!co->value)
 
489
        badcookie = TRUE;
 
490
      else
 
491
        fields++;
451
492
    }
452
 
    else if(7 != fields) {
453
 
      /* we did not find the sufficient number of fields to recognize this
454
 
         as a valid line, abort and go home */
455
 
      free_cookiemess(co);
 
493
 
 
494
    if(!badcookie && (7 != fields))
 
495
      /* we did not find the sufficient number of fields */
 
496
      badcookie = TRUE;
 
497
 
 
498
    if(badcookie) {
 
499
      freecookie(co);
456
500
      return NULL;
457
501
    }
 
502
 
458
503
  }
459
504
 
460
505
  if(!c->running &&    /* read from a file */
461
506
     c->newsession &&  /* clean session cookies */
462
507
     !co->expires) {   /* this is a session cookie since it doesn't expire! */
463
 
    free_cookiemess(co);
 
508
    freecookie(co);
464
509
    return NULL;
465
510
  }
466
511
 
498
543
          replace_old = TRUE;
499
544
        else
500
545
          replace_old = FALSE;
501
 
        
 
546
 
502
547
      }
503
548
 
504
549
      if(replace_old && !co->livecookie && clist->livecookie) {
508
553
           live cookies stay alive */
509
554
 
510
555
        /* Free the newcomer and get out of here! */
511
 
        if(co->domain)
512
 
          free(co->domain);
513
 
        if(co->path)
514
 
          free(co->path);
515
 
        if(co->name)
516
 
          free(co->name);
517
 
        if(co->value)
518
 
          free(co->value);
519
 
 
520
 
        free(co);
 
556
        freecookie(co);
521
557
        return NULL;
522
558
      }
523
559
 
592
628
                                    struct CookieInfo *inc,
593
629
                                    bool newsession)
594
630
{
595
 
  char line[MAX_COOKIE_LINE];
596
631
  struct CookieInfo *c;
597
632
  FILE *fp;
598
633
  bool fromfile=TRUE;
599
 
  
 
634
 
600
635
  if(NULL == inc) {
601
636
    /* we didn't get a struct, create one */
602
 
    c = (struct CookieInfo *)malloc(sizeof(struct CookieInfo));
 
637
    c = (struct CookieInfo *)calloc(1, sizeof(struct CookieInfo));
603
638
    if(!c)
604
639
      return NULL; /* failed to get memory */
605
 
    memset(c, 0, sizeof(struct CookieInfo));
606
640
    c->filename = strdup(file?file:"none"); /* copy the name just in case */
607
641
  }
608
642
  else {
623
657
  if(fp) {
624
658
    char *lineptr;
625
659
    bool headerline;
626
 
    while(fgets(line, MAX_COOKIE_LINE, fp)) {
627
 
      if(checkprefix("Set-Cookie:", line)) {
628
 
        /* This is a cookie line, get it! */
629
 
        lineptr=&line[11];
630
 
        headerline=TRUE;
631
 
      }
632
 
      else {
633
 
        lineptr=line;
634
 
        headerline=FALSE;
635
 
      }
636
 
      while(*lineptr && isspace((int)*lineptr))
637
 
        lineptr++;
638
 
 
639
 
      Curl_cookie_add(data, c, headerline, lineptr, NULL, NULL);
 
660
 
 
661
    char *line = (char *)malloc(MAX_COOKIE_LINE);
 
662
    if(line) {
 
663
      while(fgets(line, MAX_COOKIE_LINE, fp)) {
 
664
        if(checkprefix("Set-Cookie:", line)) {
 
665
          /* This is a cookie line, get it! */
 
666
          lineptr=&line[11];
 
667
          headerline=TRUE;
 
668
        }
 
669
        else {
 
670
          lineptr=line;
 
671
          headerline=FALSE;
 
672
        }
 
673
        while(*lineptr && my_isspace(*lineptr))
 
674
          lineptr++;
 
675
 
 
676
        Curl_cookie_add(data, c, headerline, lineptr, NULL, NULL);
 
677
      }
 
678
      free(line); /* free the line buffer */
640
679
    }
641
680
    if(fromfile)
642
681
      fclose(fp);
678
717
        continue if we are! */
679
718
     if( (co->expires<=0 || (co->expires> now)) &&
680
719
         (co->secure?secure:TRUE) ) {
681
 
       
 
720
 
682
721
       /* now check if the domain is correct */
683
722
       if(!co->domain ||
684
723
          (co->tailmatch && tailmatch(co->domain, host)) ||
685
724
          (!co->tailmatch && strequal(host, co->domain)) ) {
686
725
         /* the right part of the host matches the domain stuff in the
687
726
            cookie data */
688
 
         
 
727
 
689
728
         /* now check the left part of the path with the cookies path
690
729
            requirement */
691
730
         if(!co->path ||
693
732
 
694
733
           /* and now, we know this is a match and we should create an
695
734
              entry for the return-linked-list */
696
 
           
 
735
 
697
736
           newco = (struct Cookie *)malloc(sizeof(struct Cookie));
698
737
           if(newco) {
699
738
             /* first, copy the whole source cookie: */
701
740
 
702
741
             /* then modify our next */
703
742
             newco->next = mainco;
704
 
             
 
743
 
705
744
             /* point the main to us */
706
745
             mainco = newco;
707
746
           }
 
747
           else {
 
748
              /* failure, clear up the allocated chain and return NULL */
 
749
             while(mainco) {
 
750
               co = mainco->next;
 
751
               free(mainco);
 
752
               mainco = co;
 
753
             }
 
754
 
 
755
             return NULL;
 
756
           }
708
757
         }
709
758
       }
710
759
     }
728
777
   struct Cookie *next;
729
778
   if(co) {
730
779
      while(co) {
731
 
         next = co->next;
732
 
         free(co); /* we only free the struct since the "members" are all
733
 
                      just copied! */
734
 
         co = next;
 
780
         next = co->next;
 
781
         free(co); /* we only free the struct since the "members" are all
 
782
                      just copied! */
 
783
         co = next;
735
784
      }
736
785
   }
737
786
}
749
798
   struct Cookie *next;
750
799
   if(c) {
751
800
      if(c->filename)
752
 
         free(c->filename);
 
801
         free(c->filename);
753
802
      co = c->cookies;
754
803
 
755
804
      while(co) {
756
 
         if(co->name)
757
 
            free(co->name);
758
 
         if(co->value)
759
 
            free(co->value);
760
 
         if(co->domain)
761
 
            free(co->domain);
762
 
         if(co->path)
763
 
            free(co->path);
764
 
         if(co->expirestr)
765
 
            free(co->expirestr);
766
 
 
767
 
         if(co->version)
768
 
            free(co->version);
769
 
         if(co->maxage)
770
 
            free(co->maxage);
771
 
 
772
 
         next = co->next;
773
 
         free(co);
774
 
         co = next;
 
805
         next = co->next;
 
806
         freecookie(co);
 
807
         co = next;
775
808
      }
776
809
      free(c); /* free the base struct as well */
777
810
   }
813
846
          "# This file was generated by libcurl! Edit at your own risk.\n\n",
814
847
          out);
815
848
    co = c->cookies;
816
 
     
 
849
 
817
850
    while(co) {
818
851
      fprintf(out,
819
852
              "%s%s\t" /* domain */
845
878
  return 0;
846
879
}
847
880
 
848
 
#endif /* CURL_DISABLE_HTTP */
 
881
#endif /* CURL_DISABLE_HTTP || CURL_DISABLE_COOKIES */