Home | History | Annotate | Download | only in examples
      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