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

« back to all changes in this revision

Viewing changes to lib/hostip.c

  • Committer: Bazaar Package Importer
  • Author(s): Michael Vogt
  • Date: 2009-04-29 11:10:29 UTC
  • mfrom: (3.2.3 sid)
  • Revision ID: james.westby@ubuntu.com-20090429111029-2j5eiyokfw2bw049
Tags: 7.19.4-1ubuntu1
* Merge from debian unstable, remaining changes:
  - Drop build dependencies: stunnel, libdb4.6-dev, libssh2-1-dev
  - Add build-dependency on openssh-server
  - Drop libssh2-1-dev from libcurl4-openssl-dev's Depends.
  - Call automake-1.9 with --add-missing --copy --force
* drop debian/patches/security_CVE-2009-0037.patch 
  - this patch is part of 7.19.4

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: hostip.c,v 1.191 2008-03-11 22:55:24 bagder Exp $
 
21
 * $Id: hostip.c,v 1.214 2008-11-06 17:19:57 yangtse Exp $
22
22
 ***************************************************************************/
23
23
 
24
24
#include "setup.h"
55
55
#ifdef HAVE_SETJMP_H
56
56
#include <setjmp.h>
57
57
#endif
 
58
#ifdef HAVE_SIGNAL_H
 
59
#include <signal.h>
 
60
#endif
58
61
 
59
62
#ifdef HAVE_PROCESS_H
60
63
#include <process.h>
72
75
#define _MPRINTF_REPLACE /* use our functions only */
73
76
#include <curl/mprintf.h>
74
77
 
75
 
#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
76
 
#include "inet_ntoa_r.h"
77
 
#endif
78
 
 
79
78
#include "memory.h"
80
79
/* The last #include file should be: */
81
80
#include "memdebug.h"
82
81
 
 
82
#if defined(HAVE_ALARM) && defined(SIGALRM) && defined(HAVE_SIGSETJMP) \
 
83
    && !defined(USE_ARES)
 
84
/* alarm-based timeouts can only be used with all the dependencies satisfied */
 
85
#define USE_ALARM_TIMEOUT
 
86
#endif
 
87
 
83
88
/*
84
89
 * hostip.c explained
85
90
 * ==================
158
163
 */
159
164
int Curl_num_addresses(const Curl_addrinfo *addr)
160
165
{
161
 
  int i;
162
 
  for (i = 0; addr; addr = addr->ai_next, i++)
163
 
    ;  /* empty loop */
 
166
  int i = 0;
 
167
  while(addr) {
 
168
    addr = addr->ai_next;
 
169
    i++;
 
170
  }
164
171
  return i;
165
172
}
166
173
 
167
174
/*
168
175
 * Curl_printable_address() returns a printable version of the 1st address
169
 
 * given in the 'ip' argument. The result will be stored in the buf that is
 
176
 * given in the 'ai' argument. The result will be stored in the buf that is
170
177
 * bufsize bytes big.
171
178
 *
172
179
 * If the conversion fails, it returns NULL.
173
180
 */
174
 
const char *Curl_printable_address(const Curl_addrinfo *ip,
175
 
                                   char *buf, size_t bufsize)
 
181
const char *
 
182
Curl_printable_address(const Curl_addrinfo *ai, char *buf, size_t bufsize)
176
183
{
177
 
  const void *ip4 = &((const struct sockaddr_in*)ip->ai_addr)->sin_addr;
178
 
  int af = ip->ai_family;
179
 
#ifdef CURLRES_IPV6
180
 
  const void *ip6 = &((const struct sockaddr_in6*)ip->ai_addr)->sin6_addr;
181
 
#else
182
 
  const void *ip6 = NULL;
 
184
  const struct sockaddr_in *sa4;
 
185
  const struct in_addr *ipaddr4;
 
186
#ifdef ENABLE_IPV6
 
187
  const struct sockaddr_in6 *sa6;
 
188
  const struct in6_addr *ipaddr6;
183
189
#endif
184
190
 
185
 
  return Curl_inet_ntop(af, af == AF_INET ? ip4 : ip6, buf, bufsize);
 
191
  switch (ai->ai_family) {
 
192
    case AF_INET:
 
193
      sa4 = (const void *)ai->ai_addr;
 
194
      ipaddr4 = &sa4->sin_addr;
 
195
      return Curl_inet_ntop(ai->ai_family, (const void *)ipaddr4, buf, bufsize);
 
196
#ifdef ENABLE_IPV6
 
197
    case AF_INET6:
 
198
      sa6 = (const void *)ai->ai_addr;
 
199
      ipaddr6 = &sa6->sin6_addr;
 
200
      return Curl_inet_ntop(ai->ai_family, (const void *)ipaddr6, buf, bufsize);
 
201
#endif
 
202
    default:
 
203
      break;
 
204
  }
 
205
  return NULL;
186
206
}
187
207
 
188
208
/*
332
352
  entry_len = strlen(entry_id);
333
353
 
334
354
  /* Create a new cache entry */
335
 
  dns = (struct Curl_dns_entry *) calloc(sizeof(struct Curl_dns_entry), 1);
 
355
  dns = calloc(sizeof(struct Curl_dns_entry), 1);
336
356
  if(!dns) {
337
357
    free(entry_id);
338
358
    return NULL;
392
412
  struct SessionHandle *data = conn->data;
393
413
  CURLcode result;
394
414
  int rc = CURLRESOLV_ERROR; /* default to failure */
 
415
 
395
416
  *entry = NULL;
396
417
 
397
 
#ifdef HAVE_SIGSETJMP
398
 
  /* this allows us to time-out from the name resolver, as the timeout
399
 
     will generate a signal and we will siglongjmp() from that here */
400
 
  if(!data->set.no_signal) {
401
 
    if(sigsetjmp(curl_jmpenv, 1)) {
402
 
      /* this is coming from a siglongjmp() */
403
 
      failf(data, "name lookup timed out");
404
 
      return rc;
405
 
    }
406
 
  }
407
 
#endif
408
 
 
409
418
  /* Create an entry id, based upon the hostname and port */
410
419
  entry_id = create_hostcache_id(hostname, port);
411
420
  /* If we can't create the entry id, fail */
488
497
  return rc;
489
498
}
490
499
 
 
500
#ifdef USE_ALARM_TIMEOUT 
 
501
/*
 
502
 * This signal handler jumps back into the main libcurl code and continues
 
503
 * execution.  This effectively causes the remainder of the application to run
 
504
 * within a signal handler which is nonportable and could lead to problems.
 
505
 */
 
506
static
 
507
RETSIGTYPE alarmfunc(int sig)
 
508
{
 
509
  /* this is for "-ansi -Wall -pedantic" to stop complaining!   (rabe) */
 
510
  (void)sig;
 
511
  siglongjmp(curl_jmpenv, 1);
 
512
  return;
 
513
}
 
514
#endif /* USE_ALARM_TIMEOUT */
 
515
 
 
516
/*
 
517
 * Curl_resolv_timeout() is the same as Curl_resolv() but specifies a
 
518
 * timeout.  This function might return immediately if we're using asynch
 
519
 * resolves. See the return codes.
 
520
 *
 
521
 * The cache entry we return will get its 'inuse' counter increased when this
 
522
 * function is used. You MUST call Curl_resolv_unlock() later (when you're
 
523
 * done using this struct) to decrease the counter again.
 
524
 *
 
525
 * If built with a synchronous resolver and use of signals is not
 
526
 * disabled by the application, then a nonzero timeout will cause a
 
527
 * timeout after the specified number of milliseconds. Otherwise, timeout
 
528
 * is ignored.
 
529
 *
 
530
 * Return codes:
 
531
 *
 
532
 * CURLRESOLV_TIMEDOUT(-2) = warning, time too short or previous alarm expired
 
533
 * CURLRESOLV_ERROR   (-1) = error, no pointer
 
534
 * CURLRESOLV_RESOLVED (0) = OK, pointer provided
 
535
 * CURLRESOLV_PENDING  (1) = waiting for response, no pointer
 
536
 */
 
537
 
 
538
int Curl_resolv_timeout(struct connectdata *conn,
 
539
                        const char *hostname,
 
540
                        int port,
 
541
                        struct Curl_dns_entry **entry,
 
542
                        long timeoutms)
 
543
{
 
544
#ifdef USE_ALARM_TIMEOUT 
 
545
#ifdef HAVE_SIGACTION
 
546
  struct sigaction keep_sigact;   /* store the old struct here */
 
547
  bool keep_copysig=FALSE;        /* did copy it? */
 
548
  struct sigaction sigact;
 
549
#else
 
550
#ifdef HAVE_SIGNAL
 
551
  void (*keep_sigact)(int);       /* store the old handler here */
 
552
#endif /* HAVE_SIGNAL */
 
553
#endif /* HAVE_SIGACTION */
 
554
  volatile long timeout;
 
555
  unsigned int prev_alarm=0;
 
556
  struct SessionHandle *data = conn->data;
 
557
#endif /* USE_ALARM_TIMEOUT */
 
558
  int rc;
 
559
 
 
560
  *entry = NULL;
 
561
 
 
562
#ifdef USE_ALARM_TIMEOUT 
 
563
  if (data->set.no_signal)
 
564
    /* Ignore the timeout when signals are disabled */
 
565
    timeout = 0;
 
566
  else
 
567
    timeout = timeoutms;
 
568
 
 
569
  if(timeout && timeout < 1000)
 
570
    /* The alarm() function only provides integer second resolution, so if
 
571
       we want to wait less than one second we must bail out already now. */
 
572
    return CURLRESOLV_TIMEDOUT;
 
573
 
 
574
  if (timeout > 0) {
 
575
    /* This allows us to time-out from the name resolver, as the timeout
 
576
       will generate a signal and we will siglongjmp() from that here.
 
577
       This technique has problems (see alarmfunc). */
 
578
      if(sigsetjmp(curl_jmpenv, 1)) {
 
579
        /* this is coming from a siglongjmp() after an alarm signal */
 
580
        failf(data, "name lookup timed out");
 
581
        return CURLRESOLV_ERROR;
 
582
      }
 
583
 
 
584
    /*************************************************************
 
585
     * Set signal handler to catch SIGALRM
 
586
     * Store the old value to be able to set it back later!
 
587
     *************************************************************/
 
588
#ifdef HAVE_SIGACTION
 
589
    sigaction(SIGALRM, NULL, &sigact);
 
590
    keep_sigact = sigact;
 
591
    keep_copysig = TRUE; /* yes, we have a copy */
 
592
    sigact.sa_handler = alarmfunc;
 
593
#ifdef SA_RESTART
 
594
    /* HPUX doesn't have SA_RESTART but defaults to that behaviour! */
 
595
    sigact.sa_flags &= ~SA_RESTART;
 
596
#endif
 
597
    /* now set the new struct */
 
598
    sigaction(SIGALRM, &sigact, NULL);
 
599
#else /* HAVE_SIGACTION */
 
600
    /* no sigaction(), revert to the much lamer signal() */
 
601
#ifdef HAVE_SIGNAL
 
602
    keep_sigact = signal(SIGALRM, alarmfunc);
 
603
#endif
 
604
#endif /* HAVE_SIGACTION */
 
605
 
 
606
    /* alarm() makes a signal get sent when the timeout fires off, and that
 
607
       will abort system calls */
 
608
    prev_alarm = alarm((unsigned int) (timeout/1000L));
 
609
  }
 
610
 
 
611
#else
 
612
#ifndef CURLRES_ASYNCH
 
613
  if(timeoutms)
 
614
    infof(conn->data, "timeout on name lookup is not supported\n");
 
615
#else
 
616
  (void)timeoutms; /* timeoutms not used with an async resolver */
 
617
#endif
 
618
#endif /* USE_ALARM_TIMEOUT */
 
619
 
 
620
  /* Perform the actual name resolution. This might be interrupted by an
 
621
   * alarm if it takes too long.
 
622
   */
 
623
  rc = Curl_resolv(conn, hostname, port, entry);
 
624
 
 
625
#ifdef USE_ALARM_TIMEOUT 
 
626
  if (timeout > 0) {
 
627
 
 
628
#ifdef HAVE_SIGACTION
 
629
    if(keep_copysig) {
 
630
      /* we got a struct as it looked before, now put that one back nice
 
631
         and clean */
 
632
      sigaction(SIGALRM, &keep_sigact, NULL); /* put it back */
 
633
    }
 
634
#else
 
635
#ifdef HAVE_SIGNAL
 
636
    /* restore the previous SIGALRM handler */
 
637
    signal(SIGALRM, keep_sigact);
 
638
#endif
 
639
#endif /* HAVE_SIGACTION */
 
640
 
 
641
    /* switch back the alarm() to either zero or to what it was before minus
 
642
       the time we spent until now! */
 
643
    if(prev_alarm) {
 
644
      /* there was an alarm() set before us, now put it back */
 
645
      unsigned long elapsed_ms = Curl_tvdiff(Curl_tvnow(), conn->created);
 
646
 
 
647
      /* the alarm period is counted in even number of seconds */
 
648
      unsigned long alarm_set = prev_alarm - elapsed_ms/1000;
 
649
 
 
650
      if(!alarm_set ||
 
651
         ((alarm_set >= 0x80000000) && (prev_alarm < 0x80000000)) ) {
 
652
        /* if the alarm time-left reached zero or turned "negative" (counted
 
653
           with unsigned values), we should fire off a SIGALRM here, but we
 
654
           won't, and zero would be to switch it off so we never set it to
 
655
           less than 1! */
 
656
        alarm(1);
 
657
        rc = CURLRESOLV_TIMEDOUT;
 
658
        failf(data, "Previous alarm fired off!");
 
659
      }
 
660
      else
 
661
        alarm((unsigned int)alarm_set);
 
662
    }
 
663
    else
 
664
      alarm(0); /* just shut it off */
 
665
  }
 
666
#endif /* USE_ALARM_TIMEOUT */
 
667
 
 
668
  return rc;
 
669
}
 
670
 
491
671
/*
492
672
 * Curl_resolv_unlock() unlocks the given cached DNS entry. When this has been
493
673
 * made, the struct may be destroyed due to pruning. It is important that only
513
693
{
514
694
  struct Curl_dns_entry *p = (struct Curl_dns_entry *) freethis;
515
695
 
516
 
  Curl_freeaddrinfo(p->addr);
517
 
 
518
 
  free(p);
 
696
  if(p) {
 
697
    Curl_freeaddrinfo(p->addr);
 
698
    free(p);
 
699
  }
519
700
}
520
701
 
521
702
/*
543
724
  return Curl_he2ai(orig, port);
544
725
}
545
726
#endif /* CURLRES_ADDRINFO_COPY */
546
 
 
547
 
/***********************************************************************
548
 
 * Only for plain-ipv4 and c-ares builds
549
 
 **********************************************************************/
550
 
 
551
 
#if defined(CURLRES_IPV4) || defined(CURLRES_ARES)
552
 
/*
553
 
 * This is a function for freeing name information in a protocol independent
554
 
 * way.
555
 
 */
556
 
void Curl_freeaddrinfo(Curl_addrinfo *ai)
557
 
{
558
 
  Curl_addrinfo *next;
559
 
 
560
 
  /* walk over the list and free all entries */
561
 
  while(ai) {
562
 
    next = ai->ai_next;
563
 
    if(ai->ai_canonname)
564
 
      free(ai->ai_canonname);
565
 
    free(ai);
566
 
    ai = next;
567
 
  }
568
 
}
569
 
 
570
 
struct namebuf {
571
 
  struct hostent hostentry;
572
 
  char *h_addr_list[2];
573
 
  struct in_addr addrentry;
574
 
  char h_name[16]; /* 123.123.123.123 = 15 letters is maximum */
575
 
};
576
 
 
577
 
/*
578
 
 * Curl_ip2addr() takes a 32bit ipv4 internet address as input parameter
579
 
 * together with a pointer to the string version of the address, and it
580
 
 * returns a Curl_addrinfo chain filled in correctly with information for this
581
 
 * address/host.
582
 
 *
583
 
 * The input parameters ARE NOT checked for validity but they are expected
584
 
 * to have been checked already when this is called.
585
 
 */
586
 
Curl_addrinfo *Curl_ip2addr(in_addr_t num, const char *hostname, int port)
587
 
{
588
 
  Curl_addrinfo *ai;
589
 
 
590
 
#if defined(VMS) && \
591
 
    defined(__INITIAL_POINTER_SIZE) && (__INITIAL_POINTER_SIZE == 64)
592
 
#pragma pointer_size save
593
 
#pragma pointer_size short
594
 
#pragma message disable PTRMISMATCH
595
 
#endif
596
 
 
597
 
  struct hostent *h;
598
 
  struct in_addr *addrentry;
599
 
  struct namebuf buffer;
600
 
  struct namebuf *buf = &buffer;
601
 
 
602
 
  h = &buf->hostentry;
603
 
  h->h_addr_list = &buf->h_addr_list[0];
604
 
  addrentry = &buf->addrentry;
605
 
#ifdef _CRAYC
606
 
  /* On UNICOS, s_addr is a bit field and for some reason assigning to it
607
 
   * doesn't work.  There must be a better fix than this ugly hack.
608
 
   */
609
 
  memcpy(addrentry, &num, SIZEOF_in_addr);
610
 
#else
611
 
  addrentry->s_addr = num;
612
 
#endif
613
 
  h->h_addr_list[0] = (char*)addrentry;
614
 
  h->h_addr_list[1] = NULL;
615
 
  h->h_addrtype = AF_INET;
616
 
  h->h_length = sizeof(*addrentry);
617
 
  h->h_name = &buf->h_name[0];
618
 
  h->h_aliases = NULL;
619
 
 
620
 
  /* Now store the dotted version of the address */
621
 
  snprintf((char *)h->h_name, 16, "%s", hostname);
622
 
 
623
 
#if defined(VMS) && \
624
 
    defined(__INITIAL_POINTER_SIZE) && (__INITIAL_POINTER_SIZE == 64)
625
 
#pragma pointer_size restore
626
 
#pragma message enable PTRMISMATCH
627
 
#endif
628
 
 
629
 
  ai = Curl_he2ai(h, port);
630
 
 
631
 
  return ai;
632
 
}
633
 
#endif /* CURLRES_IPV4 || CURLRES_ARES */
634
 
 
635