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