aboutsummaryrefslogtreecommitdiff
path: root/src/daemon/digestauth.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/daemon/digestauth.c')
-rw-r--r--src/daemon/digestauth.c222
1 files changed, 221 insertions, 1 deletions
diff --git a/src/daemon/digestauth.c b/src/daemon/digestauth.c
index b2be0d9d..c0d9abc0 100644
--- a/src/daemon/digestauth.c
+++ b/src/daemon/digestauth.c
@@ -19,13 +19,15 @@
19 19
20/** 20/**
21 * @file digestauth.c 21 * @file digestauth.c
22 * @brief Implements HTTP/1.1 Digest Auth according to RFC2617 22 * @brief Implements various HTTP authentication methods
23 * @author Amr Ali 23 * @author Amr Ali
24 * @author Matthieu Speder
24 */ 25 */
25 26
26#include "platform.h" 27#include "platform.h"
27#include "internal.h" 28#include "internal.h"
28#include "md5.h" 29#include "md5.h"
30#include "base64.h"
29 31
30#define HASH_MD5_HEX_LEN (2 * MD5_DIGEST_SIZE) 32#define HASH_MD5_HEX_LEN (2 * MD5_DIGEST_SIZE)
31 33
@@ -35,6 +37,11 @@
35#define _BASE "Digest " 37#define _BASE "Digest "
36 38
37/** 39/**
40 * Beginning string for any valid Basic authentication header.
41 */
42#define _BASIC_BASE "Basic "
43
44/**
38 * Maximum length of a username for digest authentication. 45 * Maximum length of a username for digest authentication.
39 */ 46 */
40#define MAX_USERNAME_LENGTH 128 47#define MAX_USERNAME_LENGTH 128
@@ -636,5 +643,218 @@ MHD_queue_auth_fail_response(struct MHD_Connection *connection,
636 return ret; 643 return ret;
637} 644}
638 645
646/**
647 * Get the username and password from the basic authorization header sent by the client
648 *
649 * @param connection The MHD connection structure
650 * @param password a pointer for the password
651 * @return NULL if no username could be found, a pointer
652 * to the username if found
653 */
654char *
655MHD_basic_auth_get_username_password(struct MHD_Connection *connection,
656 char** password) {
657 size_t len;
658 const char *header;
659 char *decode;
660 const char *separator;
661 char *user;
662
663 header = MHD_lookup_connection_value(connection, MHD_HEADER_KIND,
664 MHD_HTTP_HEADER_AUTHORIZATION);
665 if (header == NULL)
666 return NULL;
667 if (strncmp(header, _BASIC_BASE, strlen(_BASIC_BASE)) != 0)
668 return NULL;
669 header += strlen(_BASIC_BASE);
670 decode = BASE64Decode(header);
671 if (decode == NULL) {
672#if HAVE_MESSAGES
673 MHD_DLOG(connection->daemon, "Error decoding basic authentication\n");
674#endif
675 return NULL;
676 }
677 /* Find user:password pattern */
678 separator = strstr(decode, ":");
679 if (separator == NULL) {
680#if HAVE_MESSAGES
681 MHD_DLOG(connection->daemon,
682 "Basic authentication doesn't contain ':' separator\n");
683#endif
684 free(decode);
685 return NULL;
686 }
687 user = strndup(decode, separator - decode);
688 if (password != NULL) {
689 *password = strdup(separator + 1);
690 }
691 free(decode);
692 return user;
693}
694
695/**
696 * Queues a response to request basic authentication from the client
697 *
698 * @param connection The MHD connection structure
699 * @param realm the realm presented to the client
700 * @return MHD_YES on success, MHD_NO otherwise
701 */
702int MHD_queue_basic_auth_fail_response(struct MHD_Connection *connection,
703 const char *realm, struct MHD_Response *response) {
704 int ret;
705 size_t hlen = strlen(realm) + sizeof("Basic realm=\"\"");
706 char header[hlen];
707 snprintf(header, sizeof(header), "Basic realm=\"%s\"", realm);
708 ret = MHD_add_response_header(response, MHD_HTTP_HEADER_WWW_AUTHENTICATE,
709 header);
710 if (MHD_YES == ret)
711 ret = MHD_queue_response(connection, MHD_HTTP_UNAUTHORIZED, response);
712 return ret;
713}
714
715#if HTTPS_SUPPORT
716
717/**
718 * Get the client's certificate
719 *
720 * @param connection The MHD connection structure
721 * @return NULL if no valid client certificate could be found, a pointer
722 * to the certificate if found
723 */
724void*
725MHD_cert_auth_get_certificate(struct MHD_Connection *connection) {
726
727 if (connection->client_cert == NULL && connection->client_cert_status == 0) {
728 if (connection->tls_session == NULL) {
729 connection->client_cert_status = GNUTLS_CERT_INVALID;
730 return NULL;
731 }
732
733 if (gnutls_certificate_verify_peers2(connection->tls_session,
734 &connection->client_cert_status)) {
735 connection->client_cert_status = GNUTLS_CERT_INVALID;
736 return NULL;
737 }
738
739 unsigned int listsize;
740 const gnutls_datum_t * pcert = gnutls_certificate_get_peers(
741 connection->tls_session, &listsize);
742 if (pcert == NULL || listsize == 0) {
743#if HAVE_MESSAGES
744 MHD_DLOG(connection->daemon,
745 "Failed to retrieve client certificate chain\n");
746#endif
747 connection->client_cert_status = GNUTLS_CERT_INVALID;
748 return NULL;
749 }
750
751 if (gnutls_x509_crt_init(&connection->client_cert)) {
752#if HAVE_MESSAGES
753 MHD_DLOG(connection->daemon,
754 "Failed to initialize client certificate\n");
755#endif
756 connection->client_cert = NULL;
757 connection->client_cert_status = GNUTLS_CERT_INVALID;
758 return NULL;
759 }
760 if (gnutls_x509_crt_import(connection->client_cert, &pcert[0],
761 GNUTLS_X509_FMT_DER)) {
762#if HAVE_MESSAGES
763 MHD_DLOG(connection->daemon,
764 "Failed to import client certificate\n");
765#endif
766 gnutls_x509_crt_deinit(connection->client_cert);
767 connection->client_cert = NULL;
768 connection->client_cert_status = GNUTLS_CERT_INVALID;
769 return NULL;
770 }
771 }
772
773 return connection->client_cert;
774}
775
776/**
777 * Get the distinguished name from the client's certificate
778 *
779 * @param connection The MHD connection structure
780 * @return NULL if no dn or certificate could be found, a pointer
781 * to the dn if found
782 */
783char *
784MHD_cert_auth_get_dn(struct MHD_Connection *connection) {
785
786 char* buf;
787 size_t lbuf = 0;
788
789 gnutls_x509_crt_t cert = MHD_cert_auth_get_certificate(connection);
790 if (cert == NULL)
791 return NULL;
792
793 gnutls_x509_crt_get_dn(cert, NULL, &lbuf);
794 buf = malloc(lbuf);
795 if (buf == NULL) {
796#if HAVE_MESSAGES
797 MHD_DLOG(connection->daemon,
798 "Failed to allocate memory for certificate dn\n");
799#endif
800 return NULL;
801 }
802 gnutls_x509_crt_get_dn(cert, buf, &lbuf);
803 return buf;
804
805}
806
807/**
808 * Get the alternative name of specified type from the client's certificate
809 *
810 * @param connection The MHD connection structure
811 * @param nametype The requested name type
812 * @param index The position of the alternative name if multiple names are
813 * matching the requested type, 0 for the first matching name
814 * @return NULL if no matching alternative name could be found, a pointer
815 * to the alternative name if found
816 */
817char *
818MHD_cert_auth_get_alt_name(struct MHD_Connection *connection, int nametype, unsigned int index) {
819
820 char* buf;
821 size_t lbuf;
822 unsigned int seq = 0;
823 unsigned int subseq = 0;
824 int result;
825 unsigned int type;
826
827 gnutls_x509_crt_t cert = MHD_cert_auth_get_certificate(connection);
828 if (cert == NULL)
829 return NULL;
830
831 for (;; seq++) {
832 lbuf = 0;
833 result = gnutls_x509_crt_get_subject_alt_name2(cert, seq, NULL, &lbuf,
834 &type, NULL);
835 if (result == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
836 return NULL;
837 if (type != nametype)
838 continue;
839 if (subseq != index) {
840 subseq++;
841 continue;
842 }
843 buf = malloc(lbuf);
844 if (buf == NULL) {
845#if HAVE_MESSAGES
846 MHD_DLOG(connection->daemon,
847 "Failed to allocate memory for certificate alt name\n");
848#endif
849 return NULL;
850 }
851 gnutls_x509_crt_get_subject_alt_name2(cert, seq, buf, &lbuf, NULL, NULL);
852 return buf;
853
854 }
855
856}
857
858#endif /* HTTPS */
639 859
640/* end of digestauth.c */ 860/* end of digestauth.c */