tlsauthentication.c 5.6 KB

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