Mercurial > pidgin
comparison libpurple/proxy.c @ 23992:4a1bbe955690
Add support for sending authorization for Basic proxy authentication when the
server sends a 407.
Cleanup and remove code duplication for the NTLM stuff - hopefully this doesn't
break anything as I don't have a good way to test it.
Fixes #6714
author | Daniel Atallah <daniel.atallah@gmail.com> |
---|---|
date | Wed, 27 Aug 2008 04:05:10 +0000 |
parents | 54eb782d4721 |
children | 1fb2e7951f9b |
comparison
equal
deleted
inserted
replaced
23990:62387da2a57f | 23992:4a1bbe955690 |
---|---|
775 gboolean error; | 775 gboolean error; |
776 PurpleProxyConnectData *connect_data = data; | 776 PurpleProxyConnectData *connect_data = data; |
777 char *p; | 777 char *p; |
778 gsize max_read; | 778 gsize max_read; |
779 | 779 |
780 if (connect_data->read_buffer == NULL) | 780 if (connect_data->read_buffer == NULL) { |
781 { | |
782 connect_data->read_buf_len = 8192; | 781 connect_data->read_buf_len = 8192; |
783 connect_data->read_buffer = g_malloc(connect_data->read_buf_len); | 782 connect_data->read_buffer = g_malloc(connect_data->read_buf_len); |
784 connect_data->read_len = 0; | 783 connect_data->read_len = 0; |
785 } | 784 } |
786 | 785 |
787 p = (char *)connect_data->read_buffer + connect_data->read_len; | 786 p = (char *)connect_data->read_buffer + connect_data->read_len; |
788 max_read = connect_data->read_buf_len - connect_data->read_len - 1; | 787 max_read = connect_data->read_buf_len - connect_data->read_len - 1; |
789 | 788 |
790 len = read(connect_data->fd, p, max_read); | 789 len = read(connect_data->fd, p, max_read); |
791 | 790 |
792 if (len == 0) | 791 if (len == 0) { |
793 { | |
794 purple_proxy_connect_data_disconnect(connect_data, | 792 purple_proxy_connect_data_disconnect(connect_data, |
795 _("Server closed the connection.")); | 793 _("Server closed the connection.")); |
796 return; | 794 return; |
797 } | 795 } |
798 | 796 |
799 if (len < 0) | 797 if (len < 0) { |
800 { | |
801 if (errno == EAGAIN) | 798 if (errno == EAGAIN) |
802 /* No worries */ | 799 /* No worries */ |
803 return; | 800 return; |
804 | 801 |
805 /* Error! */ | 802 /* Error! */ |
820 headers_len = len; | 817 headers_len = len; |
821 else | 818 else |
822 return; | 819 return; |
823 | 820 |
824 error = strncmp((const char *)connect_data->read_buffer, "HTTP/", 5) != 0; | 821 error = strncmp((const char *)connect_data->read_buffer, "HTTP/", 5) != 0; |
825 if (!error) | 822 if (!error) { |
826 { | |
827 int major; | 823 int major; |
828 p = (char *)connect_data->read_buffer + 5; | 824 p = (char *)connect_data->read_buffer + 5; |
829 major = strtol(p, &p, 10); | 825 major = strtol(p, &p, 10); |
830 error = (major == 0) || (*p != '.'); | 826 error = (major == 0) || (*p != '.'); |
831 if(!error) { | 827 if(!error) { |
841 } | 837 } |
842 } | 838 } |
843 | 839 |
844 /* Read the contents */ | 840 /* Read the contents */ |
845 p = g_strrstr((const gchar *)connect_data->read_buffer, "Content-Length: "); | 841 p = g_strrstr((const gchar *)connect_data->read_buffer, "Content-Length: "); |
846 if (p != NULL) | 842 if (p != NULL) { |
847 { | |
848 gchar *tmp; | 843 gchar *tmp; |
849 int len = 0; | 844 int len = 0; |
850 char tmpc; | 845 char tmpc; |
851 p += strlen("Content-Length: "); | 846 p += strlen("Content-Length: "); |
852 tmp = strchr(p, '\r'); | 847 tmp = strchr(p, '\r'); |
865 if (read(connect_data->fd, &tmpc, 1) < 0 && errno != EAGAIN) | 860 if (read(connect_data->fd, &tmpc, 1) < 0 && errno != EAGAIN) |
866 break; | 861 break; |
867 } | 862 } |
868 } | 863 } |
869 | 864 |
870 if (error) | 865 if (error) { |
871 { | |
872 purple_proxy_connect_data_disconnect_formatted(connect_data, | 866 purple_proxy_connect_data_disconnect_formatted(connect_data, |
873 _("Unable to parse response from HTTP proxy: %s\n"), | 867 _("Unable to parse response from HTTP proxy: %s\n"), |
874 connect_data->read_buffer); | 868 connect_data->read_buffer); |
875 return; | 869 return; |
876 } | 870 } |
877 else if (status != 200) | 871 else if (status != 200) { |
878 { | |
879 purple_debug_error("proxy", | 872 purple_debug_error("proxy", |
880 "Proxy server replied with:\n%s\n", | 873 "Proxy server replied with:\n%s\n", |
881 connect_data->read_buffer); | 874 connect_data->read_buffer); |
882 | 875 |
883 if (status == 407 /* Proxy Auth */) | 876 if (status == 407 /* Proxy Auth */) { |
884 { | 877 const char *header; |
885 gchar *ntlm; | 878 gchar *request; |
886 char hostname[256]; | 879 |
887 int ret; | 880 header = g_strrstr((const gchar *)connect_data->read_buffer, |
888 | 881 "Proxy-Authenticate: NTLM"); |
889 ret = gethostname(hostname, sizeof(hostname)); | 882 if (header != NULL) { |
890 hostname[sizeof(hostname) - 1] = '\0'; | 883 const char *header_end = header + strlen("Proxy-Authenticate: NTLM"); |
891 if (ret < 0 || hostname[0] == '\0') { | 884 const char *domain = purple_proxy_info_get_username(connect_data->gpi); |
892 purple_debug_warning("proxy", "gethostname() failed -- is your hostname set?"); | 885 char *username = NULL, hostname[256]; |
893 strcpy(hostname, "localhost"); | |
894 } | |
895 | |
896 ntlm = g_strrstr((const gchar *)connect_data->read_buffer, | |
897 "Proxy-Authenticate: NTLM "); | |
898 if (ntlm != NULL) | |
899 { | |
900 /* Check for Type-2 */ | |
901 gchar *tmp = ntlm; | |
902 guint8 *nonce; | |
903 gchar *domain = (gchar*)purple_proxy_info_get_username(connect_data->gpi); | |
904 gchar *username = NULL; | |
905 gchar *request; | |
906 gchar *response; | 886 gchar *response; |
887 int ret; | |
888 | |
889 ret = gethostname(hostname, sizeof(hostname)); | |
890 hostname[sizeof(hostname) - 1] = '\0'; | |
891 if (ret < 0 || hostname[0] == '\0') { | |
892 purple_debug_warning("proxy", "gethostname() failed -- is your hostname set?"); | |
893 strcpy(hostname, "localhost"); | |
894 } | |
907 | 895 |
908 if (domain != NULL) | 896 if (domain != NULL) |
909 username = strchr(domain, '\\'); | 897 username = (char*) strchr(domain, '\\'); |
910 if (username == NULL) | 898 if (username == NULL) { |
911 { | |
912 purple_proxy_connect_data_disconnect_formatted(connect_data, | 899 purple_proxy_connect_data_disconnect_formatted(connect_data, |
913 _("HTTP proxy connection error %d"), status); | 900 _("HTTP proxy connection error %d"), status); |
914 return; | 901 return; |
915 } | 902 } |
916 *username = '\0'; | 903 *username = '\0'; |
917 username++; | 904 |
918 ntlm += strlen("Proxy-Authenticate: NTLM "); | 905 /* Is there a message? */ |
919 while(*tmp != '\r' && *tmp != '\0') tmp++; | 906 if (*header_end == ' ') { |
920 *tmp = '\0'; | 907 /* Check for Type-2 */ |
921 nonce = purple_ntlm_parse_type2(ntlm, NULL); | 908 char *tmp = (char*) header; |
922 response = purple_ntlm_gen_type3(username, | 909 guint8 *nonce; |
923 (gchar*) purple_proxy_info_get_password(connect_data->gpi), | 910 |
924 hostname, | 911 header_end++; |
925 domain, nonce, NULL); | 912 username++; |
926 username--; | 913 while(*tmp != '\r' && *tmp != '\0') tmp++; |
914 *tmp = '\0'; | |
915 nonce = purple_ntlm_parse_type2(header_end, NULL); | |
916 response = purple_ntlm_gen_type3(username, | |
917 (gchar*) purple_proxy_info_get_password(connect_data->gpi), | |
918 hostname, | |
919 domain, nonce, NULL); | |
920 username--; | |
921 } else /* Empty message */ | |
922 response = purple_ntlm_gen_type1(hostname, domain); | |
923 | |
927 *username = '\\'; | 924 *username = '\\'; |
925 | |
928 request = g_strdup_printf( | 926 request = g_strdup_printf( |
929 "CONNECT %s:%d HTTP/1.1\r\n" | 927 "CONNECT %s:%d HTTP/1.1\r\n" |
930 "Host: %s:%d\r\n" | 928 "Host: %s:%d\r\n" |
931 "Proxy-Authorization: NTLM %s\r\n" | 929 "Proxy-Authorization: NTLM %s\r\n" |
932 "Proxy-Connection: Keep-Alive\r\n\r\n", | 930 "Proxy-Connection: Keep-Alive\r\n\r\n", |
933 connect_data->host, connect_data->port, connect_data->host, | 931 connect_data->host, connect_data->port, |
934 connect_data->port, response); | 932 connect_data->host, connect_data->port, |
933 response); | |
934 | |
935 g_free(response); | 935 g_free(response); |
936 | 936 |
937 g_free(connect_data->read_buffer); | 937 } else if((header = g_strrstr((const char *)connect_data->read_buffer, "Proxy-Authenticate: Basic"))) { |
938 connect_data->read_buffer = NULL; | 938 gchar *t1, *t2; |
939 | 939 |
940 connect_data->write_buffer = (guchar *)request; | 940 t1 = g_strdup_printf("%s:%s", |
941 connect_data->write_buf_len = strlen(request); | 941 purple_proxy_info_get_username(connect_data->gpi), |
942 connect_data->written_len = 0; | 942 purple_proxy_info_get_password(connect_data->gpi) ? |
943 connect_data->read_cb = http_canread; | 943 purple_proxy_info_get_password(connect_data->gpi) : ""); |
944 | 944 t2 = purple_base64_encode((const guchar *)t1, strlen(t1)); |
945 purple_input_remove(connect_data->inpa); | 945 g_free(t1); |
946 connect_data->inpa = purple_input_add(connect_data->fd, | 946 |
947 PURPLE_INPUT_WRITE, proxy_do_write, connect_data); | 947 request = g_strdup_printf( |
948 proxy_do_write(connect_data, connect_data->fd, cond); | 948 "CONNECT %s:%d HTTP/1.1\r\n" |
949 return; | 949 "Host: %s:%d\r\n" |
950 } else if((ntlm = g_strrstr((const char *)connect_data->read_buffer, "Proxy-Authenticate: NTLM"))) { /* Empty message */ | 950 "Proxy-Authorization: Basic %s\r\n", |
951 gchar *ntlm_type1; | 951 connect_data->host, connect_data->port, |
952 gchar request[2048]; | 952 connect_data->host, connect_data->port, |
953 gchar *domain = (gchar*) purple_proxy_info_get_username(connect_data->gpi); | 953 t2); |
954 gchar *username = NULL; | 954 |
955 int request_len; | 955 g_free(t2); |
956 | 956 |
957 if (domain != NULL) | |
958 username = strchr(domain, '\\'); | |
959 if (username == NULL) | |
960 { | |
961 purple_proxy_connect_data_disconnect_formatted(connect_data, | |
962 _("HTTP proxy connection error %d"), status); | |
963 return; | |
964 } | |
965 *username = '\0'; | |
966 | |
967 request_len = g_snprintf(request, sizeof(request), | |
968 "CONNECT %s:%d HTTP/1.1\r\n" | |
969 "Host: %s:%d\r\n", | |
970 connect_data->host, connect_data->port, | |
971 connect_data->host, connect_data->port); | |
972 | |
973 g_return_if_fail(request_len < sizeof(request)); | |
974 ntlm_type1 = purple_ntlm_gen_type1(hostname, domain); | |
975 request_len += g_snprintf(request + request_len, | |
976 sizeof(request) - request_len, | |
977 "Proxy-Authorization: NTLM %s\r\n" | |
978 "Proxy-Connection: Keep-Alive\r\n\r\n", | |
979 ntlm_type1); | |
980 g_free(ntlm_type1); | |
981 *username = '\\'; | |
982 | |
983 purple_input_remove(connect_data->inpa); | |
984 g_free(connect_data->read_buffer); | |
985 connect_data->read_buffer = NULL; | |
986 | |
987 connect_data->write_buffer = g_memdup(request, request_len); | |
988 connect_data->write_buf_len = request_len; | |
989 connect_data->written_len = 0; | |
990 | |
991 connect_data->read_cb = http_canread; | |
992 | |
993 connect_data->inpa = purple_input_add(connect_data->fd, | |
994 PURPLE_INPUT_WRITE, proxy_do_write, connect_data); | |
995 | |
996 proxy_do_write(connect_data, connect_data->fd, cond); | |
997 return; | |
998 } else { | 957 } else { |
999 purple_proxy_connect_data_disconnect_formatted(connect_data, | 958 purple_proxy_connect_data_disconnect_formatted(connect_data, |
1000 _("HTTP proxy connection error %d"), status); | 959 _("HTTP proxy connection error %d"), status); |
1001 return; | 960 return; |
1002 } | 961 } |
1003 } | 962 |
1004 if (status == 403) | 963 purple_input_remove(connect_data->inpa); |
1005 { | 964 g_free(connect_data->read_buffer); |
965 connect_data->read_buffer = NULL; | |
966 | |
967 connect_data->write_buffer = (guchar *)request; | |
968 connect_data->write_buf_len = strlen(request); | |
969 connect_data->written_len = 0; | |
970 | |
971 connect_data->read_cb = http_canread; | |
972 | |
973 connect_data->inpa = purple_input_add(connect_data->fd, | |
974 PURPLE_INPUT_WRITE, proxy_do_write, connect_data); | |
975 | |
976 proxy_do_write(connect_data, connect_data->fd, cond); | |
977 | |
978 return; | |
979 } | |
980 | |
981 if (status == 403) { | |
1006 /* Forbidden */ | 982 /* Forbidden */ |
1007 purple_proxy_connect_data_disconnect_formatted(connect_data, | 983 purple_proxy_connect_data_disconnect_formatted(connect_data, |
1008 _("Access denied: HTTP proxy server forbids port %d tunneling."), | 984 _("Access denied: HTTP proxy server forbids port %d tunneling."), |
1009 connect_data->port); | 985 connect_data->port); |
1010 } else { | 986 } else { |