Home | History | Annotate | Download | only in testcurl
      1 /*
      2      This file is part of libmicrohttpd
      3      Copyright (C) 2010, 2012 Christian Grothoff
      4 
      5      libmicrohttpd is free software; you can redistribute it and/or modify
      6      it under the terms of the GNU General Public License as published
      7      by the Free Software Foundation; either version 2, or (at your
      8      option) any later version.
      9 
     10      libmicrohttpd is distributed in the hope that it will be useful, but
     11      WITHOUT ANY WARRANTY; without even the implied warranty of
     12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13      General Public License for more details.
     14 
     15      You should have received a copy of the GNU General Public License
     16      along with libmicrohttpd; see the file COPYING.  If not, write to the
     17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
     18      Boston, MA 02111-1307, USA.
     19 */
     20 
     21 /**
     22  * @file daemontest_digestauth_with_arguments.c
     23  * @brief  Testcase for libmicrohttpd Digest Auth with arguments
     24  * @author Amr Ali
     25  */
     26 #include "MHD_config.h"
     27 #include "platform.h"
     28 #include <curl/curl.h>
     29 #include <microhttpd.h>
     30 #include <stdlib.h>
     31 #include <string.h>
     32 #include <time.h>
     33 #ifdef HAVE_GCRYPT_H
     34 #include <gcrypt.h>
     35 #endif
     36 
     37 #ifndef WINDOWS
     38 #include <sys/socket.h>
     39 #include <unistd.h>
     40 #else
     41 #include <wincrypt.h>
     42 #endif
     43 
     44 #define PAGE "<html><head><title>libmicrohttpd demo</title></head><body>Access granted</body></html>"
     45 
     46 #define DENIED "<html><head><title>libmicrohttpd demo</title></head><body>Access denied</body></html>"
     47 
     48 #define MY_OPAQUE "11733b200778ce33060f31c9af70a870ba96ddd4"
     49 
     50 struct CBC
     51 {
     52   char *buf;
     53   size_t pos;
     54   size_t size;
     55 };
     56 
     57 static size_t
     58 copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
     59 {
     60   struct CBC *cbc = ctx;
     61 
     62   if (cbc->pos + size * nmemb > cbc->size)
     63     return 0;                   /* overflow */
     64   memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
     65   cbc->pos += size * nmemb;
     66   return size * nmemb;
     67 }
     68 
     69 static int
     70 ahc_echo (void *cls,
     71           struct MHD_Connection *connection,
     72           const char *url,
     73           const char *method,
     74           const char *version,
     75           const char *upload_data, size_t *upload_data_size,
     76           void **unused)
     77 {
     78   struct MHD_Response *response;
     79   char *username;
     80   const char *password = "testpass";
     81   const char *realm = "test (at) example.com";
     82   int ret;
     83 
     84   username = MHD_digest_auth_get_username(connection);
     85   if ( (username == NULL) ||
     86        (0 != strcmp (username, "testuser")) )
     87     {
     88       response = MHD_create_response_from_buffer(strlen (DENIED),
     89 						 DENIED,
     90 						 MHD_RESPMEM_PERSISTENT);
     91       ret = MHD_queue_auth_fail_response(connection, realm,
     92 					 MY_OPAQUE,
     93 					 response,
     94 					 MHD_NO);
     95       MHD_destroy_response(response);
     96       return ret;
     97     }
     98   ret = MHD_digest_auth_check(connection, realm,
     99 			      username,
    100 			      password,
    101 			      300);
    102   free(username);
    103   if ( (ret == MHD_INVALID_NONCE) ||
    104        (ret == MHD_NO) )
    105     {
    106       response = MHD_create_response_from_buffer(strlen (DENIED),
    107 						 DENIED,
    108 						 MHD_RESPMEM_PERSISTENT);
    109       if (NULL == response)
    110 	return MHD_NO;
    111       ret = MHD_queue_auth_fail_response(connection, realm,
    112 					 MY_OPAQUE,
    113 					 response,
    114 					 (ret == MHD_INVALID_NONCE) ? MHD_YES : MHD_NO);
    115       MHD_destroy_response(response);
    116       return ret;
    117     }
    118   response = MHD_create_response_from_buffer(strlen(PAGE), PAGE,
    119 					     MHD_RESPMEM_PERSISTENT);
    120   ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
    121   MHD_destroy_response(response);
    122   return ret;
    123 }
    124 
    125 
    126 static int
    127 testDigestAuth ()
    128 {
    129   int fd;
    130   CURL *c;
    131   CURLcode errornum;
    132   struct MHD_Daemon *d;
    133   struct CBC cbc;
    134   size_t len;
    135   size_t off = 0;
    136   char buf[2048];
    137   char rnd[8];
    138 
    139   cbc.buf = buf;
    140   cbc.size = 2048;
    141   cbc.pos = 0;
    142 #ifndef WINDOWS
    143   fd = open("/dev/urandom", O_RDONLY);
    144   if (-1 == fd)
    145     {
    146 	  fprintf(stderr, "Failed to open `%s': %s\n",
    147 	       "/dev/urandom",
    148 		   strerror(errno));
    149 	  return 1;
    150 	}
    151   while (off < 8)
    152 	{
    153 	  len = read(fd, rnd, 8);
    154 	  if (len == -1)
    155 	    {
    156 		  fprintf(stderr, "Failed to read `%s': %s\n",
    157 		       "/dev/urandom",
    158 			   strerror(errno));
    159 		  (void) close(fd);
    160 		  return 1;
    161 		}
    162 	  off += len;
    163 	}
    164   (void) close(fd);
    165 #else
    166   {
    167     HCRYPTPROV cc;
    168     BOOL b;
    169     b = CryptAcquireContext (&cc, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
    170     if (b == 0)
    171     {
    172       fprintf (stderr, "Failed to acquire crypto provider context: %lu\n",
    173           GetLastError ());
    174       return 1;
    175     }
    176     b = CryptGenRandom (cc, 8, rnd);
    177     if (b == 0)
    178     {
    179       fprintf (stderr, "Failed to generate 8 random bytes: %lu\n",
    180           GetLastError ());
    181     }
    182     CryptReleaseContext (cc, 0);
    183     if (b == 0)
    184       return 1;
    185   }
    186 #endif
    187   d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
    188                         1337, NULL, NULL, &ahc_echo, PAGE,
    189 			MHD_OPTION_DIGEST_AUTH_RANDOM, sizeof (rnd), rnd,
    190 			MHD_OPTION_NONCE_NC_SIZE, 300,
    191 			MHD_OPTION_END);
    192   if (d == NULL)
    193     return 1;
    194   c = curl_easy_init ();
    195   curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:1337/foo?key=value");
    196   curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
    197   curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
    198   curl_easy_setopt (c, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
    199   curl_easy_setopt (c, CURLOPT_USERPWD, "testuser:testpass");
    200   curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
    201   curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
    202   curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
    203   curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
    204   /* NOTE: use of CONNECTTIMEOUT without also
    205      setting NOSIGNAL results in really weird
    206      crashes on my system!*/
    207   curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
    208   if (CURLE_OK != (errornum = curl_easy_perform (c)))
    209     {
    210       fprintf (stderr,
    211                "curl_easy_perform failed: `%s'\n",
    212                curl_easy_strerror (errornum));
    213       curl_easy_cleanup (c);
    214       MHD_stop_daemon (d);
    215       return 2;
    216     }
    217   curl_easy_cleanup (c);
    218   MHD_stop_daemon (d);
    219   if (cbc.pos != strlen (PAGE))
    220     return 4;
    221   if (0 != strncmp (PAGE, cbc.buf, strlen (PAGE)))
    222     return 8;
    223   return 0;
    224 }
    225 
    226 
    227 int
    228 main (int argc, char *const *argv)
    229 {
    230   unsigned int errorCount = 0;
    231 
    232 #ifdef HAVE_GCRYPT_H
    233   gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
    234 #ifdef GCRYCTL_INITIALIZATION_FINISHED
    235   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
    236 #endif
    237 #endif
    238   if (0 != curl_global_init (CURL_GLOBAL_WIN32))
    239     return 2;
    240   errorCount += testDigestAuth ();
    241   if (errorCount != 0)
    242     fprintf (stderr, "Error (code: %u)\n", errorCount);
    243   curl_global_cleanup ();
    244   return errorCount != 0;       /* 0 == pass */
    245 }
    246