libmicrohttpd

HTTP/1.x server C library (MHD 1.x, stable)
Log | Files | Refs | Submodules | README | LICENSE

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