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 {