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