digest_auth_example.c (6154B)
1 /* 2 This file is part of libmicrohttpd 3 Copyright (C) 2010 Christian Grothoff (and other contributing authors) 4 Copyright (C) 2016-2024 Evgeny Grin (Karlson2k) 5 6 This library is free software; you can redistribute it and/or 7 modify it under the terms of the GNU Lesser General Public 8 License as published by the Free Software Foundation; either 9 version 2.1 of the License, or (at your option) any later version. 10 11 This library is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 Lesser General Public License for more details. 15 16 You should have received a copy of the GNU Lesser General Public 17 License along with this library; if not, write to the Free Software 18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 */ 20 /** 21 * @file digest_auth_example.c 22 * @brief minimal example for how to use digest auth with libmicrohttpd 23 * @author Amr Ali 24 * @author Karlson2k (Evgeny Grin) 25 */ 26 27 #include "platform.h" 28 #include <microhttpd.h> 29 #include <stdlib.h> 30 #include <stdio.h> 31 #include <errno.h> 32 #if defined(_WIN32) && ! defined(__CYGWIN__) 33 # include <wincrypt.h> 34 #endif /* _WIN32 && ! __CYGWIN__ */ 35 36 37 #define PAGE \ 38 "<html><head><title>libmicrohttpd demo</title></head>" \ 39 "<body>Access granted</body></html>" 40 41 #define DENIED \ 42 "<html><head><title>libmicrohttpd demo</title></head>" \ 43 "<body>Access denied</body></html>" 44 45 #define MY_OPAQUE_STR "11733b200778ce33060f31c9af70a870ba96ddd4" 46 47 static enum MHD_Result 48 ahc_echo (void *cls, 49 struct MHD_Connection *connection, 50 const char *url, 51 const char *method, 52 const char *version, 53 const char *upload_data, size_t *upload_data_size, void **req_cls) 54 { 55 struct MHD_Response *response; 56 /* Only one user has access to the page */ 57 static const char *username = "testuser"; 58 static const char *password = "testpass"; 59 static const char *realm = "test@example.com"; 60 enum MHD_DigestAuthResult res_e; 61 enum MHD_Result ret; 62 static int already_called_marker; 63 (void) cls; /* Unused. Silent compiler warning. */ 64 (void) url; /* Unused. Silent compiler warning. */ 65 (void) method; /* Unused. Silent compiler warning. */ 66 (void) version; /* Unused. Silent compiler warning. */ 67 (void) upload_data; /* Unused. Silent compiler warning. */ 68 (void) upload_data_size; /* Unused. Silent compiler warning. */ 69 70 if (&already_called_marker != *req_cls) 71 { /* Called for the first time, request not fully read yet */ 72 *req_cls = &already_called_marker; 73 /* Wait for complete request */ 74 return MHD_YES; 75 } 76 77 /* No need to call MHD_digest_auth_get_username3() as the only 78 * one user has an access. The username match is checked by 79 * MHD_digest_auth_check3() function. */ 80 res_e = MHD_digest_auth_check3 ( 81 connection, 82 realm, 83 username, 84 password, 85 0, 0, 86 MHD_DIGEST_AUTH_MULT_QOP_ANY_NON_INT, 87 MHD_DIGEST_AUTH_MULT_ALGO3_ANY_NON_SESSION); 88 if (res_e != MHD_DAUTH_OK) 89 { 90 response = 91 MHD_create_response_from_buffer_static (strlen (DENIED), 92 DENIED); 93 if (NULL == response) 94 return MHD_NO; 95 ret = MHD_queue_auth_required_response3 ( 96 connection, 97 realm, 98 MY_OPAQUE_STR, 99 NULL, 100 response, 101 (res_e == MHD_DAUTH_NONCE_STALE) ? MHD_YES : MHD_NO, 102 MHD_DIGEST_AUTH_MULT_QOP_ANY_NON_INT, 103 MHD_DIGEST_AUTH_MULT_ALGO3_ANY_NON_SESSION, 104 MHD_NO, 105 MHD_YES); 106 107 MHD_destroy_response (response); 108 return ret; 109 } 110 response = MHD_create_response_from_buffer_static (strlen (PAGE), PAGE); 111 ret = MHD_queue_response (connection, MHD_HTTP_OK, response); 112 MHD_destroy_response (response); 113 return ret; 114 } 115 116 117 int 118 main (int argc, char *const *argv) 119 { 120 char rnd[8]; 121 struct MHD_Daemon *d; 122 unsigned int port; 123 124 if ( (argc != 2) || 125 (1 != sscanf (argv[1], "%u", &port)) || 126 (65535 < port) ) 127 { 128 fprintf (stderr, "%s PORT\n", argv[0]); 129 return 1; 130 } 131 132 if (1) 133 { 134 #if ! defined(_WIN32) || defined(__CYGWIN__) 135 int fd; 136 ssize_t len; 137 size_t off; 138 139 fd = open ("/dev/urandom", O_RDONLY); 140 if (-1 == fd) 141 { 142 fprintf (stderr, "Failed to open `%s': %s\n", 143 "/dev/urandom", 144 strerror (errno)); 145 return 1; 146 } 147 for (off = 0; off < sizeof(rnd); off += (size_t) len) 148 { 149 len = read (fd, rnd, 8); 150 if (0 > len) 151 { 152 fprintf (stderr, "Failed to read `%s': %s\n", 153 "/dev/urandom", 154 strerror (errno)); 155 (void) close (fd); 156 return 1; 157 } 158 } 159 (void) close (fd); 160 #else /* Native W32 */ 161 HCRYPTPROV cc; 162 BOOL b; 163 164 b = CryptAcquireContext (&cc, 165 NULL, 166 NULL, 167 PROV_RSA_FULL, 168 CRYPT_VERIFYCONTEXT); 169 if (FALSE == b) 170 { 171 fprintf (stderr, 172 "Failed to acquire crypto provider context: %lu\n", 173 (unsigned long) GetLastError ()); 174 return 1; 175 } 176 b = CryptGenRandom (cc, sizeof(rnd), (BYTE *) rnd); 177 if (FALSE == b) 178 { 179 fprintf (stderr, 180 "Failed to generate 8 random bytes: %lu\n", 181 GetLastError ()); 182 } 183 CryptReleaseContext (cc, 0); 184 if (FALSE == b) 185 return 1; 186 #endif /* Native W32 */ 187 } 188 189 d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION 190 | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG, 191 (uint16_t) port, 192 NULL, NULL, &ahc_echo, NULL, 193 MHD_OPTION_DIGEST_AUTH_RANDOM, sizeof(rnd), rnd, 194 MHD_OPTION_NONCE_NC_SIZE, 300, 195 MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 120, 196 MHD_OPTION_END); 197 if (d == NULL) 198 return 1; 199 (void) getc (stdin); 200 MHD_stop_daemon (d); 201 return 0; 202 } 203 204 205 /* end of digest_auth_example.c */