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