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 * 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 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 * 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 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 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 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 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 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