• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Feel free to use this example code in any way
2    you see fit (Public Domain) */
3 
4 #include <sys/types.h>
5 #ifndef _WIN32
6 #include <sys/select.h>
7 #include <sys/socket.h>
8 #else
9 #include <winsock2.h>
10 #endif
11 #include <microhttpd.h>
12 #include <string.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 
16 #define PORT 8888
17 
18 #define REALM     "\"Maintenance\""
19 #define USER      "a legitimate user"
20 #define PASSWORD  "and his password"
21 
22 #define SERVERKEYFILE "server.key"
23 #define SERVERCERTFILE "server.pem"
24 
25 
26 static char *
string_to_base64(const char * message)27 string_to_base64 (const char *message)
28 {
29   const char *lookup =
30     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
31   unsigned long l;
32   int i;
33   char *tmp;
34   size_t length = strlen (message);
35 
36   tmp = malloc (length * 2);
37   if (NULL == tmp)
38     return tmp;
39 
40   tmp[0] = 0;
41 
42   for (i = 0; i < length; i += 3)
43     {
44       l = (((unsigned long) message[i]) << 16)
45         | (((i + 1) < length) ? (((unsigned long) message[i + 1]) << 8) : 0)
46         | (((i + 2) < length) ? ((unsigned long) message[i + 2]) : 0);
47 
48 
49       strncat (tmp, &lookup[(l >> 18) & 0x3F], 1);
50       strncat (tmp, &lookup[(l >> 12) & 0x3F], 1);
51 
52       if (i + 1 < length)
53         strncat (tmp, &lookup[(l >> 6) & 0x3F], 1);
54       if (i + 2 < length)
55         strncat (tmp, &lookup[l & 0x3F], 1);
56     }
57 
58   if (length % 3)
59     strncat (tmp, "===", 3 - length % 3);
60 
61   return tmp;
62 }
63 
64 
65 static long
get_file_size(const char * filename)66 get_file_size (const char *filename)
67 {
68   FILE *fp;
69 
70   fp = fopen (filename, "rb");
71   if (fp)
72     {
73       long size;
74 
75       if ((0 != fseek (fp, 0, SEEK_END)) || (-1 == (size = ftell (fp))))
76         size = 0;
77 
78       fclose (fp);
79 
80       return size;
81     }
82   else
83     return 0;
84 }
85 
86 static char *
load_file(const char * filename)87 load_file (const char *filename)
88 {
89   FILE *fp;
90   char *buffer;
91   long size;
92 
93   size = get_file_size (filename);
94   if (size == 0)
95     return NULL;
96 
97   fp = fopen (filename, "rb");
98   if (!fp)
99     return NULL;
100 
101   buffer = malloc (size);
102   if (!buffer)
103     {
104       fclose (fp);
105       return NULL;
106     }
107 
108   if (size != fread (buffer, 1, size, fp))
109     {
110       free (buffer);
111       buffer = NULL;
112     }
113 
114   fclose (fp);
115   return buffer;
116 }
117 
118 static int
ask_for_authentication(struct MHD_Connection * connection,const char * realm)119 ask_for_authentication (struct MHD_Connection *connection, const char *realm)
120 {
121   int ret;
122   struct MHD_Response *response;
123   char *headervalue;
124   const char *strbase = "Basic realm=";
125 
126   response = MHD_create_response_from_buffer (0, NULL,
127 					      MHD_RESPMEM_PERSISTENT);
128   if (!response)
129     return MHD_NO;
130 
131   headervalue = malloc (strlen (strbase) + strlen (realm) + 1);
132   if (!headervalue)
133     return MHD_NO;
134 
135   strcpy (headervalue, strbase);
136   strcat (headervalue, realm);
137 
138   ret = MHD_add_response_header (response, "WWW-Authenticate", headervalue);
139   free (headervalue);
140   if (!ret)
141     {
142       MHD_destroy_response (response);
143       return MHD_NO;
144     }
145 
146   ret = MHD_queue_response (connection, MHD_HTTP_UNAUTHORIZED, response);
147 
148   MHD_destroy_response (response);
149 
150   return ret;
151 }
152 
153 static int
is_authenticated(struct MHD_Connection * connection,const char * username,const char * password)154 is_authenticated (struct MHD_Connection *connection,
155                   const char *username, const char *password)
156 {
157   const char *headervalue;
158   char *expected_b64, *expected;
159   const char *strbase = "Basic ";
160   int authenticated;
161 
162   headervalue =
163     MHD_lookup_connection_value (connection, MHD_HEADER_KIND,
164                                  "Authorization");
165   if (NULL == headervalue)
166     return 0;
167   if (0 != strncmp (headervalue, strbase, strlen (strbase)))
168     return 0;
169 
170   expected = malloc (strlen (username) + 1 + strlen (password) + 1);
171   if (NULL == expected)
172     return 0;
173 
174   strcpy (expected, username);
175   strcat (expected, ":");
176   strcat (expected, password);
177 
178   expected_b64 = string_to_base64 (expected);
179   free (expected);
180   if (NULL == expected_b64)
181     return 0;
182 
183   authenticated =
184     (strcmp (headervalue + strlen (strbase), expected_b64) == 0);
185 
186   free (expected_b64);
187 
188   return authenticated;
189 }
190 
191 
192 static int
secret_page(struct MHD_Connection * connection)193 secret_page (struct MHD_Connection *connection)
194 {
195   int ret;
196   struct MHD_Response *response;
197   const char *page = "<html><body>A secret.</body></html>";
198 
199   response =
200     MHD_create_response_from_buffer (strlen (page), (void *) page,
201 				     MHD_RESPMEM_PERSISTENT);
202   if (!response)
203     return MHD_NO;
204 
205   ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
206   MHD_destroy_response (response);
207 
208   return ret;
209 }
210 
211 
212 static int
answer_to_connection(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 ** con_cls)213 answer_to_connection (void *cls, struct MHD_Connection *connection,
214                       const char *url, const char *method,
215                       const char *version, const char *upload_data,
216                       size_t *upload_data_size, void **con_cls)
217 {
218   if (0 != strcmp (method, "GET"))
219     return MHD_NO;
220   if (NULL == *con_cls)
221     {
222       *con_cls = connection;
223       return MHD_YES;
224     }
225 
226   if (!is_authenticated (connection, USER, PASSWORD))
227     return ask_for_authentication (connection, REALM);
228 
229   return secret_page (connection);
230 }
231 
232 
233 int
main()234 main ()
235 {
236   struct MHD_Daemon *daemon;
237   char *key_pem;
238   char *cert_pem;
239 
240   key_pem = load_file (SERVERKEYFILE);
241   cert_pem = load_file (SERVERCERTFILE);
242 
243   if ((key_pem == NULL) || (cert_pem == NULL))
244     {
245       printf ("The key/certificate files could not be read.\n");
246       return 1;
247     }
248 
249   daemon =
250     MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_SSL, PORT, NULL,
251                       NULL, &answer_to_connection, NULL,
252                       MHD_OPTION_HTTPS_MEM_KEY, key_pem,
253                       MHD_OPTION_HTTPS_MEM_CERT, cert_pem, MHD_OPTION_END);
254   if (NULL == daemon)
255     {
256       printf ("%s\n", cert_pem);
257 
258       free (key_pem);
259       free (cert_pem);
260 
261       return 1;
262     }
263 
264   (void) getchar ();
265 
266   MHD_stop_daemon (daemon);
267   free (key_pem);
268   free (cert_pem);
269 
270   return 0;
271 }
272