tlsauthentication.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  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. size_t i;
  27. char *tmp;
  28. size_t length = strlen (message);
  29. tmp = malloc (length * 2 + 1);
  30. if (NULL == tmp)
  31. return NULL;
  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 != (long)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. size_t slen;
  99. const char *strbase = "Basic realm=";
  100. response = MHD_create_response_from_buffer (0, NULL,
  101. MHD_RESPMEM_PERSISTENT);
  102. if (!response)
  103. return MHD_NO;
  104. slen = strlen (strbase) + strlen (realm) + 1;
  105. if (NULL == (headervalue = malloc (slen)))
  106. return MHD_NO;
  107. snprintf (headervalue,
  108. slen,
  109. "%s%s",
  110. strbase,
  111. realm);
  112. ret = MHD_add_response_header (response,
  113. "WWW-Authenticate",
  114. headervalue);
  115. free (headervalue);
  116. if (! ret)
  117. {
  118. MHD_destroy_response (response);
  119. return MHD_NO;
  120. }
  121. ret = MHD_queue_response (connection,
  122. MHD_HTTP_UNAUTHORIZED,
  123. response);
  124. MHD_destroy_response (response);
  125. return ret;
  126. }
  127. static int
  128. is_authenticated (struct MHD_Connection *connection,
  129. const char *username,
  130. const char *password)
  131. {
  132. const char *headervalue;
  133. char *expected_b64;
  134. char *expected;
  135. const char *strbase = "Basic ";
  136. int authenticated;
  137. size_t slen;
  138. headervalue =
  139. MHD_lookup_connection_value (connection, MHD_HEADER_KIND,
  140. "Authorization");
  141. if (NULL == headervalue)
  142. return 0;
  143. if (0 != strncmp (headervalue, strbase, strlen (strbase)))
  144. return 0;
  145. slen = strlen (username) + 1 + strlen (password) + 1;
  146. if (NULL == (expected = malloc (slen)))
  147. return 0;
  148. snprintf (expected,
  149. slen,
  150. "%s:%s",
  151. username,
  152. password);
  153. expected_b64 = string_to_base64 (expected);
  154. free (expected);
  155. if (NULL == expected_b64)
  156. return 0;
  157. authenticated =
  158. (strcmp (headervalue + strlen (strbase), expected_b64) == 0);
  159. free (expected_b64);
  160. return authenticated;
  161. }
  162. static int
  163. secret_page (struct MHD_Connection *connection)
  164. {
  165. int ret;
  166. struct MHD_Response *response;
  167. const char *page = "<html><body>A secret.</body></html>";
  168. response =
  169. MHD_create_response_from_buffer (strlen (page), (void *) page,
  170. MHD_RESPMEM_PERSISTENT);
  171. if (!response)
  172. return MHD_NO;
  173. ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
  174. MHD_destroy_response (response);
  175. return ret;
  176. }
  177. static int
  178. answer_to_connection (void *cls, struct MHD_Connection *connection,
  179. const char *url, const char *method,
  180. const char *version, const char *upload_data,
  181. size_t *upload_data_size, void **con_cls)
  182. {
  183. (void)cls; /* Unused. Silent compiler warning. */
  184. (void)url; /* Unused. Silent compiler warning. */
  185. (void)version; /* Unused. Silent compiler warning. */
  186. (void)upload_data; /* Unused. Silent compiler warning. */
  187. (void)upload_data_size; /* Unused. Silent compiler warning. */
  188. if (0 != strcmp (method, "GET"))
  189. return MHD_NO;
  190. if (NULL == *con_cls)
  191. {
  192. *con_cls = connection;
  193. return MHD_YES;
  194. }
  195. if (!is_authenticated (connection, USER, PASSWORD))
  196. return ask_for_authentication (connection, REALM);
  197. return secret_page (connection);
  198. }
  199. int
  200. main ()
  201. {
  202. struct MHD_Daemon *daemon;
  203. char *key_pem;
  204. char *cert_pem;
  205. key_pem = load_file (SERVERKEYFILE);
  206. cert_pem = load_file (SERVERCERTFILE);
  207. if ((key_pem == NULL) || (cert_pem == NULL))
  208. {
  209. printf ("The key/certificate files could not be read.\n");
  210. if (NULL != key_pem)
  211. free (key_pem);
  212. if (NULL != cert_pem)
  213. free (cert_pem);
  214. return 1;
  215. }
  216. daemon =
  217. MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_TLS, PORT, NULL,
  218. NULL, &answer_to_connection, NULL,
  219. MHD_OPTION_HTTPS_MEM_KEY, key_pem,
  220. MHD_OPTION_HTTPS_MEM_CERT, cert_pem, MHD_OPTION_END);
  221. if (NULL == daemon)
  222. {
  223. printf ("%s\n", cert_pem);
  224. free (key_pem);
  225. free (cert_pem);
  226. return 1;
  227. }
  228. (void) getchar ();
  229. MHD_stop_daemon (daemon);
  230. free (key_pem);
  231. free (cert_pem);
  232. return 0;
  233. }