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

« back to all changes in this revision

Viewing changes to lib/hostthre.c

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

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19
19
 * KIND, either express or implied.
20
20
 *
21
 
 * $Id: hostthre.c,v 1.23 2005/04/26 13:08:49 bagder Exp $
 
21
 * $Id: hostthre.c,v 1.33 2005/11/24 20:39:00 bagder Exp $
22
22
 ***************************************************************************/
23
23
 
24
24
#include "setup.h"
88
88
/* The last #include file should be: */
89
89
#include "memdebug.h"
90
90
 
 
91
#if defined(_MSC_VER) && defined(CURL_NO__BEGINTHREADEX)
 
92
#pragma message ("No _beginthreadex() available in this RTL")
 
93
#endif
 
94
 
91
95
/***********************************************************************
92
96
 * Only for Windows threaded name resolves builds
93
97
 **********************************************************************/
157
161
  FILE *stderr_file;
158
162
  HANDLE mutex_waiting;  /* marks that we are still waiting for a resolve */
159
163
  HANDLE event_resolved; /* marks that the thread obtained the information */
 
164
  HANDLE event_thread_started; /* marks that the thread has initialized and
 
165
                                  started */
 
166
  HANDLE mutex_terminate; /* serializes access to flag_terminate */
 
167
  HANDLE event_terminate; /* flag for thread to terminate instead of calling
 
168
                             callbacks */
160
169
#ifdef CURLRES_IPV6
161
170
  struct addrinfo hints;
162
171
#endif
163
172
};
164
173
 
 
174
/* Data for synchronization between resolver thread and its parent */
 
175
struct thread_sync_data {
 
176
  HANDLE mutex_waiting;   /* thread_data.mutex_waiting duplicate */
 
177
  HANDLE mutex_terminate; /* thread_data.mutex_terminate duplicate */
 
178
  HANDLE event_terminate; /* thread_data.event_terminate duplicate */
 
179
  char * hostname;        /* hostname to resolve, Curl_async.hostname
 
180
                             duplicate */
 
181
};
 
182
 
 
183
/* Destroy resolver thread synchronization data */
 
184
static
 
185
void destroy_thread_sync_data(struct thread_sync_data * tsd)
 
186
{
 
187
  if (tsd->hostname) {
 
188
    free(tsd->hostname);
 
189
    tsd->hostname = NULL;
 
190
  }
 
191
  if (tsd->event_terminate) {
 
192
    CloseHandle(tsd->event_terminate);
 
193
    tsd->event_terminate = NULL;
 
194
  }
 
195
  if (tsd->mutex_terminate) {
 
196
    CloseHandle(tsd->mutex_terminate);
 
197
    tsd->mutex_terminate = NULL;
 
198
  }
 
199
  if (tsd->mutex_waiting) {
 
200
    CloseHandle(tsd->mutex_waiting);
 
201
    tsd->mutex_waiting = NULL;
 
202
  }
 
203
}
 
204
 
 
205
/* Initialize resolver thread synchronization data */
 
206
static
 
207
BOOL init_thread_sync_data(struct thread_data * td,
 
208
                           char * hostname,
 
209
                           struct thread_sync_data * tsd)
 
210
{
 
211
  HANDLE curr_proc = GetCurrentProcess();
 
212
 
 
213
  memset(tsd, 0, sizeof(tsd));
 
214
  if (!DuplicateHandle(curr_proc, td->mutex_waiting,
 
215
                       curr_proc, &tsd->mutex_waiting, 0, FALSE,
 
216
                       DUPLICATE_SAME_ACCESS)) {
 
217
    /* failed to duplicate the mutex, no point in continuing */
 
218
    destroy_thread_sync_data(tsd);
 
219
    return FALSE;
 
220
  }
 
221
  if (!DuplicateHandle(curr_proc, td->mutex_terminate,
 
222
                       curr_proc, &tsd->mutex_terminate, 0, FALSE,
 
223
                       DUPLICATE_SAME_ACCESS)) {
 
224
    /* failed to duplicate the mutex, no point in continuing */
 
225
    destroy_thread_sync_data(tsd);
 
226
    return FALSE;
 
227
  }
 
228
  if (!DuplicateHandle(curr_proc, td->event_terminate,
 
229
                       curr_proc, &tsd->event_terminate, 0, FALSE,
 
230
                       DUPLICATE_SAME_ACCESS)) {
 
231
    /* failed to duplicate the event, no point in continuing */
 
232
    destroy_thread_sync_data(tsd);
 
233
    return FALSE;
 
234
  }
 
235
  /* Copying hostname string because original can be destroyed by parent
 
236
   * thread during gethostbyname execution.
 
237
   */
 
238
  tsd->hostname = strdup(hostname);
 
239
  if (!tsd->hostname) {
 
240
    /* Memory allocation failed */
 
241
    destroy_thread_sync_data(tsd);
 
242
    return FALSE;
 
243
  }
 
244
  return TRUE;
 
245
}
 
246
 
 
247
/* acquire resolver thread synchronization */
 
248
static
 
249
BOOL acquire_thread_sync(struct thread_sync_data * tsd)
 
250
{
 
251
  /* is the thread initiator still waiting for us ? */
 
252
  if (WaitForSingleObject(tsd->mutex_waiting, 0) == WAIT_TIMEOUT) {
 
253
    /* yes, it is */
 
254
 
 
255
    /* Waiting access to event_terminate */
 
256
    if (WaitForSingleObject(tsd->mutex_terminate, INFINITE) != WAIT_OBJECT_0) {
 
257
      /* Something went wrong - now just ignoring */
 
258
    }
 
259
    else {
 
260
      if (WaitForSingleObject(tsd->event_terminate, 0) != WAIT_TIMEOUT) {
 
261
        /* Parent thread signaled us to terminate.
 
262
         * This means that all data in conn->async is now destroyed
 
263
         * and we cannot use it.
 
264
         */
 
265
      }
 
266
      else {
 
267
        return TRUE;
 
268
      }
 
269
    }
 
270
  }
 
271
  return FALSE;
 
272
}
 
273
 
 
274
/* release resolver thread synchronization */
 
275
static
 
276
void release_thread_sync(struct thread_sync_data * tsd)
 
277
{
 
278
  ReleaseMutex(tsd->mutex_terminate);
 
279
}
 
280
 
165
281
#if defined(CURLRES_IPV4)
166
282
/*
167
283
 * gethostbyname_thread() resolves a name, calls the Curl_addrinfo4_callback
177
293
  struct hostent *he;
178
294
  int    rc = 0;
179
295
 
180
 
  /* Duplicate the passed mutex handle.
 
296
  /* Duplicate the passed mutex and event handles.
181
297
   * This allows us to use it even after the container gets destroyed
182
298
   * due to a resolver timeout.
183
299
   */
184
 
  HANDLE mutex_waiting = NULL;
185
 
  HANDLE curr_proc = GetCurrentProcess();
186
 
 
187
 
  if (!DuplicateHandle(curr_proc, td->mutex_waiting,
188
 
                       curr_proc, &mutex_waiting, 0, FALSE,
189
 
                       DUPLICATE_SAME_ACCESS)) {
190
 
    /* failed to duplicate the mutex, no point in continuing */
 
300
  struct thread_sync_data tsd = { 0,0,0,NULL };
 
301
  if (!init_thread_sync_data(td, conn->async.hostname, &tsd)) {
 
302
    /* thread synchronization data initialization failed */
191
303
    return -1;
192
304
  }
193
305
 
200
312
#endif
201
313
 
202
314
  WSASetLastError (conn->async.status = NO_DATA); /* pending status */
203
 
  he = gethostbyname (conn->async.hostname);
204
 
 
205
 
  /* is the thread initiator still waiting for us ? */
206
 
  if (WaitForSingleObject(mutex_waiting, 0) == WAIT_TIMEOUT) {
207
 
    /* yes, it is */
208
 
 
209
 
    /* Mark that we have obtained the information, and that we are
210
 
     * calling back with it.
211
 
     */
 
315
 
 
316
  /* Signaling that we have initialized all copies of data and handles we
 
317
     need */
 
318
  SetEvent(td->event_thread_started);
 
319
 
 
320
  he = gethostbyname (tsd.hostname);
 
321
 
 
322
  /* is parent thread waiting for us and are we able to access conn members? */
 
323
  if (acquire_thread_sync(&tsd)) {
 
324
    /* Mark that we have obtained the information, and that we are calling
 
325
     * back with it. */
212
326
    SetEvent(td->event_resolved);
213
 
 
214
327
    if (he) {
215
328
      rc = Curl_addrinfo4_callback(conn, CURL_ASYNC_SUCCESS, he);
216
329
    }
219
332
    }
220
333
    TRACE(("Winsock-error %d, addr %s\n", conn->async.status,
221
334
           he ? inet_ntoa(*(struct in_addr*)he->h_addr) : "unknown"));
 
335
    release_thread_sync(&tsd);
222
336
  }
223
337
 
224
338
  /* clean up */
225
 
  CloseHandle(mutex_waiting);
 
339
  destroy_thread_sync_data(&tsd);
226
340
 
227
341
  return (rc);
228
342
  /* An implicit _endthreadex() here */
244
358
  struct addrinfo    *res;
245
359
  char   service [NI_MAXSERV];
246
360
  int    rc;
 
361
  struct addrinfo hints = td->hints;
247
362
 
248
363
  /* Duplicate the passed mutex handle.
249
364
   * This allows us to use it even after the container gets destroyed
250
365
   * due to a resolver timeout.
251
366
   */
252
 
  HANDLE mutex_waiting = NULL;
253
 
  HANDLE curr_proc = GetCurrentProcess();
254
 
 
255
 
  if (!DuplicateHandle(curr_proc, td->mutex_waiting,
256
 
                       curr_proc, &mutex_waiting, 0, FALSE,
257
 
                       DUPLICATE_SAME_ACCESS)) {
258
 
    /* failed to duplicate the mutex, no point in continuing */
 
367
  struct thread_sync_data tsd = { 0,0,0,NULL };
 
368
  if (!init_thread_sync_data(td, conn->async.hostname, &tsd)) {
 
369
    /* thread synchronization data initialization failed */
259
370
    return -1;
260
371
  }
261
372
 
267
378
 
268
379
  WSASetLastError(conn->async.status = NO_DATA); /* pending status */
269
380
 
270
 
  rc = getaddrinfo(conn->async.hostname, service, &td->hints, &res);
271
 
 
272
 
  /* is the thread initiator still waiting for us ? */
273
 
  if (WaitForSingleObject(mutex_waiting, 0) == WAIT_TIMEOUT) {
274
 
    /* yes, it is */
275
 
 
276
 
    /* Mark that we have obtained the information, and that we are
277
 
     * calling back with it.
278
 
     */
 
381
  /* Signaling that we have initialized all copies of data and handles we
 
382
     need */
 
383
  SetEvent(td->event_thread_started);
 
384
 
 
385
  rc = getaddrinfo(tsd.hostname, service, &hints, &res);
 
386
 
 
387
  /* is parent thread waiting for us and are we able to access conn members? */
 
388
  if (acquire_thread_sync(&tsd)) {
 
389
    /* Mark that we have obtained the information, and that we are calling
 
390
       back with it. */
279
391
    SetEvent(td->event_resolved);
280
392
 
281
393
    if (rc == 0) {
288
400
      rc = Curl_addrinfo6_callback(conn, (int)WSAGetLastError(), NULL);
289
401
      TRACE(("Winsock-error %d, no address\n", conn->async.status));
290
402
    }
 
403
    release_thread_sync(&tsd);
291
404
  }
292
405
 
293
406
  /* clean up */
294
 
  CloseHandle(mutex_waiting);
 
407
  destroy_thread_sync_data(&tsd);
295
408
 
296
409
  return (rc);
297
410
  /* An implicit _endthreadex() here */
299
412
#endif
300
413
 
301
414
/*
302
 
 * Curl_destroy_thread_data() cleans up async resolver data.
 
415
 * Curl_destroy_thread_data() cleans up async resolver data and thread handle.
303
416
 * Complementary of ares_destroy.
304
417
 */
305
418
void Curl_destroy_thread_data (struct Curl_async *async)
311
424
    struct thread_data *td = (struct thread_data*) async->os_specific;
312
425
    curl_socket_t sock = td->dummy_sock;
313
426
 
 
427
    if (td->mutex_terminate && td->event_terminate) {
 
428
      /* Signaling resolver thread to terminate */
 
429
      if (WaitForSingleObject(td->mutex_terminate, INFINITE) == WAIT_OBJECT_0) {
 
430
        SetEvent(td->event_terminate);
 
431
        ReleaseMutex(td->mutex_terminate);
 
432
      }
 
433
      else {
 
434
        /* Something went wrong - just ignoring it */
 
435
      }
 
436
    }
 
437
 
 
438
    if (td->mutex_terminate)
 
439
      CloseHandle(td->mutex_terminate);
 
440
    if (td->event_terminate)
 
441
      CloseHandle(td->event_terminate);
 
442
    if (td->event_thread_started)
 
443
      CloseHandle(td->event_thread_started);
 
444
 
314
445
    if (sock != CURL_SOCKET_BAD)
315
446
      sclose(sock);
316
447
 
321
452
    if (td->event_resolved)
322
453
      CloseHandle(td->event_resolved);
323
454
 
 
455
    if (td->thread_hnd)
 
456
      CloseHandle(td->thread_hnd);
 
457
 
324
458
    free(async->os_specific);
325
459
  }
326
460
  async->hostname = NULL;
338
472
                                 const Curl_addrinfo *hints)
339
473
{
340
474
  struct thread_data *td = calloc(sizeof(*td), 1);
 
475
  HANDLE thread_and_event[2] = {0};
341
476
 
342
477
  if (!td) {
343
478
    SetLastError(ENOMEM);
378
513
    SetLastError(EAGAIN);
379
514
    return FALSE;
380
515
  }
 
516
  /* Create the mutex used to serialize access to event_terminated
 
517
   * between us and resolver thread.
 
518
   */
 
519
  td->mutex_terminate = CreateMutex(NULL, FALSE, NULL);
 
520
  if (td->mutex_terminate == NULL) {
 
521
    Curl_destroy_thread_data(&conn->async);
 
522
    SetLastError(EAGAIN);
 
523
    return FALSE;
 
524
  }
 
525
  /* Create the event used to signal thread that it should terminate.
 
526
   */
 
527
  td->event_terminate = CreateEvent(NULL, TRUE, FALSE, NULL);
 
528
  if (td->event_terminate == NULL) {
 
529
    Curl_destroy_thread_data(&conn->async);
 
530
    SetLastError(EAGAIN);
 
531
    return FALSE;
 
532
  }
 
533
  /* Create the event used by thread to inform it has initialized its own data.
 
534
   */
 
535
  td->event_thread_started = CreateEvent(NULL, TRUE, FALSE, NULL);
 
536
  if (td->event_thread_started == NULL) {
 
537
    Curl_destroy_thread_data(&conn->async);
 
538
    SetLastError(EAGAIN);
 
539
    return FALSE;
 
540
  }
381
541
 
382
542
  td->stderr_file = stderr;
383
543
 
403
563
     Curl_destroy_thread_data(&conn->async);
404
564
     return FALSE;
405
565
  }
 
566
  /* Waiting until the thread will initialize its data or it will exit due errors.
 
567
   */
 
568
  thread_and_event[0] = td->thread_hnd;
 
569
  thread_and_event[1] = td->event_thread_started;
 
570
  if (WaitForMultipleObjects(sizeof(thread_and_event) /
 
571
                             sizeof(thread_and_event[0]),
 
572
                             thread_and_event, FALSE,
 
573
                             INFINITE) == WAIT_FAILED) {
 
574
    /* The resolver thread has been created,
 
575
     * most probably it works now - ignoring this "minor" error
 
576
     */
 
577
  }
406
578
  /* This socket is only to keep Curl_resolv_fdset() and select() happy;
407
579
   * should never become signalled for read/write since it's unbound but
408
580
   * Windows needs atleast 1 socket in select().
481
653
 
482
654
  TRACE(("elapsed %lu ms\n", GetTickCount()-ticks));
483
655
 
484
 
  CloseHandle(td->thread_hnd);
485
 
 
486
656
  if(entry)
487
657
    *entry = conn->async.dns;
488
658
 
494
664
      rc = CURLE_OUT_OF_MEMORY;
495
665
      failf(data, "Could not resolve host: %s", curl_easy_strerror(rc));
496
666
    }
 
667
    else if(conn->async.done) {
 
668
      if(conn->bits.httpproxy) {
 
669
        failf(data, "Could not resolve proxy: %s; %s",
 
670
              conn->proxy.dispname, Curl_strerror(conn, conn->async.status));
 
671
        rc = CURLE_COULDNT_RESOLVE_PROXY;
 
672
      }
 
673
      else {
 
674
        failf(data, "Could not resolve host: %s; %s",
 
675
              conn->host.name, Curl_strerror(conn, conn->async.status));
 
676
        rc = CURLE_COULDNT_RESOLVE_HOST;
 
677
      }
 
678
    }
497
679
    else if (td->thread_status == (DWORD)-1 || conn->async.status == NO_DATA) {
498
680
      failf(data, "Resolving host timed out: %s", conn->host.name);
499
681
      rc = CURLE_OPERATION_TIMEDOUT;
500
682
    }
501
 
    else if(conn->async.done) {
502
 
      failf(data, "Could not resolve host: %s; %s",
503
 
            conn->host.name, Curl_strerror(conn,conn->async.status));
504
 
      rc = CURLE_COULDNT_RESOLVE_HOST;
505
 
    }
506
683
    else
507
684
      rc = CURLE_OPERATION_TIMEDOUT;
508
685
  }
645
822
 
646
823
  memset(&hints, 0, sizeof(hints));
647
824
  hints.ai_family = pf;
648
 
  hints.ai_socktype = SOCK_STREAM;
 
825
  hints.ai_socktype = conn->socktype;
 
826
#if 0 /* removed nov 8 2005 before 7.15.1 */
649
827
  hints.ai_flags = AI_CANONNAME;
 
828
#endif
650
829
  itoa(port, sbuf, 10);
651
830
 
652
831
  /* fire up a new resolver thread! */