ali@14: /* ali@14: * A program to explore http support on MS-Windows. ali@14: */ ali@14: ali@14: #include "config.h" ali@14: #include ali@14: #include ali@14: #include ali@14: #include ali@14: #if HAVE_WINHTTP_H ali@14: #include ali@14: #include ali@14: #include ali@14: ali@14: #ifndef PKCS12_NO_PERSIST_KEY ali@14: #define PKCS12_NO_PERSIST_KEY 0x00008000 ali@14: #endif ali@14: ali@14: static gboolean debug=FALSE; ali@14: ali@14: static GOptionEntry entries[] = ali@14: { ali@14: { "debug",'d',0,G_OPTION_ARG_NONE,&debug,"Output debugging",NULL }, ali@14: { NULL } ali@14: }; ali@14: ali@14: static struct WinHttpFuncs ali@14: { ali@14: WINBOOL (WINAPI *AddRequestHeaders)(HINTERNET,LPCWSTR,DWORD,DWORD); ali@14: WINBOOL (WINAPI *DetectAutoProxyConfigUrl)(DWORD,LPWSTR*); ali@14: WINBOOL (WINAPI *CheckPlatform)(void); ali@14: WINBOOL (WINAPI *CloseHandle)(HINTERNET); ali@14: HINTERNET (WINAPI *Connect)(HINTERNET,LPCWSTR,INTERNET_PORT,DWORD); ali@14: WINBOOL (WINAPI *CrackUrl)(LPCWSTR,DWORD,DWORD,LPURL_COMPONENTS); ali@14: WINBOOL (WINAPI *CreateUrl)(LPURL_COMPONENTS,DWORD,LPWSTR,LPDWORD); ali@14: WINBOOL (WINAPI *GetDefaultProxyConfiguration)(WINHTTP_PROXY_INFO*); ali@14: WINBOOL (WINAPI *GetIEProxyConfigForCurrentUser)(WINHTTP_CURRENT_USER_IE_PROXY_CONFIG*); ali@14: WINBOOL (WINAPI *GetProxyForUrl)(HINTERNET,LPCWSTR,WINHTTP_AUTOPROXY_OPTIONS*,WINHTTP_PROXY_INFO*); ali@14: HINTERNET (WINAPI *Open)(LPCWSTR,DWORD,LPCWSTR,LPCWSTR,DWORD); ali@14: HINTERNET (WINAPI *OpenRequest)(HINTERNET,LPCWSTR,LPCWSTR,LPCWSTR,LPCWSTR,LPCWSTR*,DWORD); ali@14: WINBOOL (WINAPI *QueryAuthParams)(HINTERNET,DWORD,LPVOID*); ali@14: WINBOOL (WINAPI *QueryAuthSchemes)(HINTERNET,LPDWORD,LPDWORD,LPDWORD); ali@14: WINBOOL (WINAPI *QueryDataAvailable)(HINTERNET,LPDWORD); ali@14: WINBOOL (WINAPI *QueryHeaders)(HINTERNET,DWORD,LPCWSTR,LPVOID,LPDWORD,LPDWORD); ali@14: WINBOOL (WINAPI *QueryOption)(HINTERNET,DWORD,LPVOID,LPDWORD); ali@14: WINBOOL (WINAPI *ReadData)(HINTERNET,LPVOID,DWORD,LPDWORD); ali@14: WINBOOL (WINAPI *ReceiveResponse)(HINTERNET,LPVOID); ali@14: WINBOOL (WINAPI *SendRequest)(HINTERNET,LPCWSTR,DWORD,LPVOID,DWORD,DWORD,DWORD_PTR); ali@14: WINBOOL (WINAPI *SetDefaultProxyConfiguration)(WINHTTP_PROXY_INFO*); ali@14: WINBOOL (WINAPI *SetCredentials)(HINTERNET,DWORD,DWORD,LPCWSTR,LPCWSTR,LPVOID); ali@14: WINBOOL (WINAPI *SetOption)(HINTERNET,DWORD,LPVOID,DWORD); ali@14: WINHTTP_STATUS_CALLBACK (WINAPI *SetStatusCallback)(HINTERNET,WINHTTP_STATUS_CALLBACK,DWORD,DWORD_PTR); ali@14: WINBOOL (WINAPI *SetTimeouts)(HINTERNET,int,int,int,int); ali@14: WINBOOL (WINAPI *TimeFromSystemTime)(CONST SYSTEMTIME *,LPWSTR); ali@14: WINBOOL (WINAPI *TimeToSystemTime)(LPCWSTR,SYSTEMTIME*); ali@14: WINBOOL (WINAPI *WriteData)(HINTERNET,LPCVOID,DWORD,LPDWORD); ali@14: } WinHttp; ali@14: ali@14: static int plover_init_winhttp(void) ali@14: { ali@14: HMODULE module; ali@14: if (WinHttp.Open) ali@14: return 0; ali@14: module=LoadLibraryA("winhttp.dll"); ali@14: if (!module) ali@14: return -1; ali@14: WinHttp.AddRequestHeaders= ali@14: (WINBOOL (WINAPI *)(HINTERNET,LPCWSTR,DWORD,DWORD)) ali@14: GetProcAddress(module,"WinHttpAddRequestHeaders"); ali@14: WinHttp.DetectAutoProxyConfigUrl= ali@14: (WINBOOL (WINAPI *)(DWORD,LPWSTR*)) ali@14: GetProcAddress(module,"WinHttpDetectAutoProxyConfigUrl"); ali@14: WinHttp.CheckPlatform=(WINBOOL (WINAPI *)(void)) ali@14: GetProcAddress(module,"WinHttpCheckPlatform"); ali@14: WinHttp.CloseHandle=(WINBOOL (WINAPI *)(HINTERNET)) ali@14: GetProcAddress(module,"WinHttpCloseHandle"); ali@14: WinHttp.Connect= ali@14: (HINTERNET (WINAPI *)(HINTERNET,LPCWSTR,INTERNET_PORT,DWORD)) ali@14: GetProcAddress(module,"WinHttpConnect"); ali@14: WinHttp.CrackUrl=(WINBOOL (WINAPI *)(LPCWSTR,DWORD,DWORD,LPURL_COMPONENTS)) ali@14: GetProcAddress(module,"WinHttpCrackUrl"); ali@14: WinHttp.CreateUrl= ali@14: (WINBOOL (WINAPI *)(LPURL_COMPONENTS,DWORD,LPWSTR,LPDWORD)) ali@14: GetProcAddress(module,"WinHttpCreateUrl"); ali@14: WinHttp.GetDefaultProxyConfiguration= ali@14: (WINBOOL (WINAPI *)(WINHTTP_PROXY_INFO*)) ali@14: GetProcAddress(module,"WinHttpGetDefaultProxyConfiguration"); ali@14: WinHttp.GetIEProxyConfigForCurrentUser= ali@14: (WINBOOL (WINAPI *)(WINHTTP_CURRENT_USER_IE_PROXY_CONFIG*)) ali@14: GetProcAddress(module,"WinHttpGetIEProxyConfigForCurrentUser"); ali@14: WinHttp.GetProxyForUrl= ali@14: (WINBOOL (WINAPI *)(HINTERNET,LPCWSTR,WINHTTP_AUTOPROXY_OPTIONS*,WINHTTP_PROXY_INFO*)) ali@14: GetProcAddress(module,"WinHttpGetProxyForUrl"); ali@14: WinHttp.Open=(HINTERNET (WINAPI *)(LPCWSTR,DWORD,LPCWSTR,LPCWSTR,DWORD)) ali@14: GetProcAddress(module,"WinHttpOpen"); ali@14: WinHttp.OpenRequest= ali@14: (HINTERNET (WINAPI *)(HINTERNET,LPCWSTR,LPCWSTR,LPCWSTR,LPCWSTR,LPCWSTR*,DWORD)) ali@14: GetProcAddress(module,"WinHttpOpenRequest"); ali@14: WinHttp.QueryAuthParams=(WINBOOL (WINAPI *)(HINTERNET,DWORD,LPVOID*)) ali@14: GetProcAddress(module,"WinHttpQueryAuthParams"); ali@14: WinHttp.QueryAuthSchemes= ali@14: (WINBOOL (WINAPI *)(HINTERNET,LPDWORD,LPDWORD,LPDWORD)) ali@14: GetProcAddress(module,"WinHttpQueryAuthSchemes"); ali@14: WinHttp.QueryDataAvailable=(WINBOOL (WINAPI *)(HINTERNET,LPDWORD)) ali@14: GetProcAddress(module,"WinHttpQueryDataAvailable"); ali@14: WinHttp.QueryHeaders= ali@14: (WINBOOL (WINAPI *)(HINTERNET,DWORD,LPCWSTR,LPVOID,LPDWORD,LPDWORD)) ali@14: GetProcAddress(module,"WinHttpQueryHeaders"); ali@14: WinHttp.QueryOption=(WINBOOL (WINAPI *)(HINTERNET,DWORD,LPVOID,LPDWORD)) ali@14: GetProcAddress(module,"WinHttpQueryOption"); ali@14: WinHttp.ReadData=(WINBOOL (WINAPI *)(HINTERNET,LPVOID,DWORD,LPDWORD)) ali@14: GetProcAddress(module,"WinHttpReadData"); ali@14: WinHttp.ReceiveResponse=(WINBOOL (WINAPI *)(HINTERNET,LPVOID)) ali@14: GetProcAddress(module,"WinHttpReceiveResponse"); ali@14: WinHttp.SendRequest= ali@14: (WINBOOL (WINAPI *)(HINTERNET,LPCWSTR,DWORD,LPVOID,DWORD,DWORD,DWORD_PTR)) ali@14: GetProcAddress(module,"WinHttpSendRequest"); ali@14: WinHttp.SetDefaultProxyConfiguration= ali@14: (WINBOOL (WINAPI *)(WINHTTP_PROXY_INFO*)) ali@14: GetProcAddress(module,"WinHttpSetDefaultProxyConfiguration"); ali@14: WinHttp.SetCredentials= ali@14: (WINBOOL (WINAPI *)(HINTERNET,DWORD,DWORD,LPCWSTR,LPCWSTR,LPVOID)) ali@14: GetProcAddress(module,"WinHttpSetCredentials"); ali@14: WinHttp.SetOption=(WINBOOL (WINAPI *)(HINTERNET,DWORD,LPVOID,DWORD)) ali@14: GetProcAddress(module,"WinHttpSetOption"); ali@14: WinHttp.SetStatusCallback= ali@14: (WINHTTP_STATUS_CALLBACK (WINAPI *)(HINTERNET,WINHTTP_STATUS_CALLBACK,DWORD,DWORD_PTR)) ali@14: GetProcAddress(module,"WinHttpSetStatusCallback"); ali@14: WinHttp.SetTimeouts=(WINBOOL (WINAPI *)(HINTERNET,int,int,int,int)) ali@14: GetProcAddress(module,"WinHttpSetTimeouts"); ali@14: WinHttp.TimeFromSystemTime=(WINBOOL (WINAPI *)(CONST SYSTEMTIME *,LPWSTR)) ali@14: GetProcAddress(module,"WinHttpTimeFromSystemTime"); ali@14: WinHttp.TimeToSystemTime=(WINBOOL (WINAPI *)(LPCWSTR,SYSTEMTIME*)) ali@14: GetProcAddress(module,"WinHttpTimeToSystemTime"); ali@14: WinHttp.WriteData=(WINBOOL (WINAPI *)(HINTERNET,LPCVOID,DWORD,LPDWORD)) ali@14: GetProcAddress(module,"WinHttpWriteData"); ali@14: if (!WinHttp.CrackUrl || !WinHttp.Open || !WinHttp.Connect || ali@14: !WinHttp.OpenRequest || !WinHttp.SendRequest || ali@14: !WinHttp.ReceiveResponse || !WinHttp.QueryDataAvailable || ali@14: !WinHttp.ReadData || !WinHttp.CloseHandle) ali@14: { ali@14: FreeLibrary(module); ali@14: WinHttp.Open=NULL; ali@14: return -1; ali@14: } ali@14: return 0; ali@14: } ali@14: ali@14: /* ali@14: * This will find ${PREFIX}/${file} if it exists, but it may also ali@14: * find ${PREFIX}/.../${file} if ${PREFIX}/${file} does not exist. ali@14: * This seems unlikely and won't do any harm should it occur. ali@14: */ ali@14: ali@14: gchar *find_prefixed_file(const char *file) ali@14: { ali@14: int i,len; ali@14: const char *name; ali@14: char *install_root; ali@14: struct razor_set *set; ali@24: struct razor_error *error=NULL; ali@14: struct razor_package *package; ali@14: struct razor_package_iterator *pi; ali@14: struct razor_file_iterator *fi; ali@14: gchar *retval=NULL; ali@14: len=strlen(file); ali@14: install_root=getenv("RAZOR_ROOT"); ali@14: if (!install_root) ali@14: install_root=""; ali@24: set=razor_root_open_read_only(install_root,&error); ali@14: if (set) ali@14: { ali@14: pi=razor_package_iterator_create(set); ali@14: while (razor_package_iterator_next(pi,&package,RAZOR_DETAIL_LAST)) ali@14: { ali@14: fi=razor_file_iterator_create(set,package,0); ali@14: while (!retval && razor_file_iterator_next(fi,&name)) ali@14: { ali@14: i=strlen(name)-len; ali@14: if (i>0 && name[i-1]=='/' && !strcmp(name+i,file)) ali@14: { ali@14: if (!retval || strlen(retval)>strlen(name)) ali@14: { ali@14: g_free(retval); ali@14: retval=g_strdup(name); ali@14: } ali@14: } ali@14: } ali@14: razor_file_iterator_destroy(fi); ali@14: } ali@14: razor_package_iterator_destroy(pi); ali@14: razor_set_unref(set); ali@14: } ali@24: if (error) ali@24: razor_error_free(error); ali@14: return retval; ali@14: } ali@14: ali@14: static HCERTSTORE plover_p12_import(const char *file,const wchar_t *password) ali@14: { ali@14: GError *error=NULL; ali@14: gchar *p12,*path,*s; ali@14: gsize len; ali@14: CRYPT_DATA_BLOB pfx; ali@14: HCERTSTORE store; ali@14: s=g_build_path("/","etc","pki",file,NULL); ali@14: path=find_prefixed_file(s); ali@14: if (!path) ali@14: { ali@14: g_printerr("%s: Not installed\n",s); ali@14: g_free(s); ali@14: return NULL; ali@14: } ali@14: g_free(s); ali@14: if (!g_file_get_contents(path,&p12,&len,&error)) ali@14: { ali@14: g_printerr("%s: %s\n",path,error->message); ali@14: g_free(path); ali@14: g_error_free(error); ali@14: return NULL; ali@14: } ali@14: g_free(path); ali@14: pfx.pbData=(BYTE *)p12; ali@14: pfx.cbData=len; ali@14: store=PFXImportCertStore(&pfx,password,PKCS12_NO_PERSIST_KEY); ali@14: if (!store) ali@14: g_printerr("PFXImportCertStore failed. Err: %lu\n",GetLastError()); ali@14: g_free(p12); ali@14: return store; ali@14: } ali@14: ali@14: static const CERT_CONTEXT *plover_get_client_certificate(HCERTSTORE store) ali@14: { ali@14: const CERT_CONTEXT *iter,*cert; ali@14: cert=NULL; ali@14: iter=CertEnumCertificatesInStore(store,NULL); ali@14: while(iter) ali@14: { ali@14: if (!cert) ali@14: cert=CertDuplicateCertificateContext(iter); ali@14: iter=CertEnumCertificatesInStore(store,iter); ali@14: } ali@14: return cert; ali@14: } ali@14: ali@14: void CALLBACK plover_status_callback(HINTERNET handle,DWORD_PTR context, ali@14: DWORD status,LPVOID status_information,DWORD status_information_length) ali@14: { ali@14: g_printerr("CB status 0x%lX",status); ali@14: if (status==WINHTTP_CALLBACK_STATUS_SECURE_FAILURE) ali@14: g_printerr(", flag 0x%lX",*(DWORD *)status_information); ali@14: g_printerr("\n"); ali@14: } ali@14: ali@14: int fetch(HINTERNET session,HCERTSTORE store,const char *url) ali@14: { ali@14: URL_COMPONENTS components={0}; ali@14: HINTERNET connection,request; ali@14: DWORD len,nb,options; ali@14: char *buffer; ali@14: wchar_t *ws; ali@14: glong ws_len; ali@14: gchar *hostname,*path; ali@14: const CERT_CONTEXT *client_cert; ali@14: components.dwStructSize=sizeof(components); ali@14: components.dwSchemeLength=(DWORD)-1; ali@14: components.dwHostNameLength=(DWORD)-1; ali@14: components.dwUserNameLength=(DWORD)-1; ali@14: components.dwPasswordLength=(DWORD)-1; ali@14: components.dwUrlPathLength=(DWORD)-1; ali@14: ws=g_utf8_to_utf16(url,-1,NULL,&ws_len,NULL); ali@14: if (!ws || !WinHttp.CrackUrl(ws,ws_len,0,&components)) ali@14: { ali@14: g_printerr("%s: Invalid or unsupported URL\n",url); ali@14: return -1; ali@14: } ali@14: /* ICU_REJECT_USERPWD is not supported under Windows XP */ ali@14: if (components.dwUserNameLength || components.dwPasswordLength) ali@14: { ali@14: g_printerr("%s: Credentials not supported\n",url); ali@14: return -1; ali@14: } ali@14: hostname=g_utf16_to_utf8(components.lpszHostName, ali@14: components.dwHostNameLength,NULL,NULL,NULL); ali@14: path=g_utf16_to_utf8(components.lpszUrlPath,components.dwUrlPathLength,NULL, ali@14: NULL,NULL); ali@14: g_free(ws); ali@14: ws=g_utf8_to_utf16(hostname,-1,NULL,NULL,NULL); ali@14: connection=WinHttp.Connect(session,ws, ali@14: components.nPort?components.nPort:INTERNET_DEFAULT_PORT,0); ali@14: g_free(ws); ali@14: if (connection) ali@14: { ali@14: ws=g_utf8_to_utf16(path,-1,NULL,NULL,NULL); ali@14: request=WinHttp.OpenRequest(connection,L"GET",ws,NULL, ali@14: WINHTTP_NO_REFERER,WINHTTP_DEFAULT_ACCEPT_TYPES, ali@14: components.nScheme==INTERNET_SCHEME_HTTPS?WINHTTP_FLAG_SECURE:0); ali@14: g_free(ws); ali@14: if (request) ali@14: { ali@14: if (debug) ali@14: (void)WinHttp.SetStatusCallback(request,plover_status_callback, ali@14: WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS,0); ali@14: if (components.nScheme==INTERNET_SCHEME_HTTPS && WinHttp.SetOption) ali@14: { ali@14: options=SECURITY_FLAG_IGNORE_UNKNOWN_CA; ali@14: (void)WinHttp.SetOption(request,WINHTTP_OPTION_SECURITY_FLAGS, ali@14: &options,sizeof(options)); ali@14: client_cert=plover_get_client_certificate(store); ali@14: if (client_cert) ali@14: { ali@14: if (!WinHttp.SetOption(request, ali@14: WINHTTP_OPTION_CLIENT_CERT_CONTEXT,(void *)client_cert, ali@14: sizeof(*client_cert))) ali@14: g_printerr("Failed to set client certificate (%lu)\n", ali@14: GetLastError()); ali@14: } ali@14: else ali@14: g_printerr("No client certificate found\n"); ali@14: } ali@14: if (!WinHttp.SendRequest(request,WINHTTP_NO_ADDITIONAL_HEADERS, ali@14: 0,WINHTTP_NO_REQUEST_DATA,0,0,0)) ali@14: g_printerr("Failed to send request (%lu)\n",GetLastError()); ali@14: else if (!WinHttp.ReceiveResponse(request,NULL)) ali@14: g_printerr("Failed to receive response (%lu)\n",GetLastError()); ali@14: else ali@14: { ali@14: do ali@14: { ali@14: len=0; ali@14: if (!WinHttp.QueryDataAvailable(request,&len)) ali@14: g_printerr( ali@14: "Error %lu in WinHttpQueryDataAvailable.\n", ali@14: (unsigned long)GetLastError()); ali@14: buffer=calloc(len+1,1); ali@14: if (!buffer) ali@14: break; ali@14: else ali@14: { ali@14: if (!WinHttp.ReadData(request,(void *)buffer,len,&nb)) ali@14: g_printerr("Error %lu in WinHttpReadData.\n", ali@14: (unsigned long)GetLastError()); ali@14: else ali@14: printf("%s\n",buffer); ali@14: free(buffer); ali@14: } ali@14: } while (len>0); ali@14: } ali@14: WinHttp.CloseHandle(request); ali@14: } ali@14: else ali@14: g_printerr("Failed to open request for %s (%lu)\n",path, ali@14: GetLastError()); ali@14: WinHttp.CloseHandle(connection); ali@14: } ali@14: else ali@14: g_printerr("Failed to open connection to %s\n",hostname); ali@14: g_free(hostname); ali@14: g_free(path); ali@14: return 0; ali@14: } ali@14: ali@14: int main(int argc,char **argv) ali@14: { ali@14: GError *error=NULL; ali@14: GOptionContext *context; ali@14: HCERTSTORE store; ali@14: HINTERNET session; ali@14: wchar_t *ws; ali@14: context=g_option_context_new("URL - fetch a URL"); ali@14: g_option_context_add_main_entries(context,entries,NULL); ali@14: if (!g_option_context_parse(context,&argc,&argv,&error)) ali@14: { ali@14: g_printerr("Option parsing failed: %s\n",error->message); ali@14: exit(1); ali@14: } ali@14: if (argc!=2) ali@14: { ali@14: g_printerr("%s\n",g_option_context_get_help(context,TRUE,NULL)); ali@14: exit(1); ali@14: } ali@14: if (plover_init_winhttp()) ali@14: { ali@14: g_printerr("HTTP is not supported on this machine\n"); ali@14: exit(1); ali@14: } ali@14: store=plover_p12_import("system.p12",L"xyzzy-ylem"); ali@14: if (!store) ali@14: exit(1); ali@14: ws=g_utf8_to_utf16(PACKAGE_NAME "/" PACKAGE_VERSION,-1,NULL,NULL,NULL); ali@14: session=WinHttp.Open(ws,WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, ali@14: WINHTTP_NO_PROXY_NAME,WINHTTP_NO_PROXY_BYPASS,0); ali@14: free(ws); ali@14: if (!session) ali@14: { ali@14: g_printerr("Failed to open WinHttp session\n"); ali@14: exit(1); ali@14: } ali@14: if (fetch(session,store,argv[1])) ali@14: exit(1); ali@14: WinHttp.CloseHandle(session); ali@14: CertCloseStore(store,CERT_CLOSE_STORE_FORCE_FLAG); ali@14: exit(0); ali@14: } ali@14: #else /* !HAVE_WINHTTP_H */ ali@14: main() ali@14: { ali@14: g_printerr("HTTP is not supported on this machine\n"); ali@14: exit(1); ali@14: } ali@14: #endif /* HAVE_WINHTTP_H */