• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
copyBuffer(void * ptr,size_t size,size_t nmemb,void * ctx)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
ahc_echo(void * cls,struct MHD_Connection * connection,const char * url,const char * method,const char * version,const char * upload_data,size_t * upload_data_size,void ** unused)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@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
testDigestAuth()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
main(int argc,char * const * argv)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