diff options
Diffstat (limited to 'src/daemon/digestauth.c')
-rw-r--r-- | src/daemon/digestauth.c | 222 |
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 | */ | ||
654 | char * | ||
655 | MHD_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 | */ | ||
702 | int 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 | */ | ||
724 | void* | ||
725 | MHD_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 | */ | ||
783 | char * | ||
784 | MHD_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 | */ | ||
817 | char * | ||
818 | MHD_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 */ |