Fix bug causing a transaction without a base to be treated as a programming error
2 * A program to explore http support on MS-Windows.
15 #ifndef PKCS12_NO_PERSIST_KEY
16 #define PKCS12_NO_PERSIST_KEY 0x00008000
19 static gboolean debug=FALSE;
21 static GOptionEntry entries[] =
23 { "debug",'d',0,G_OPTION_ARG_NONE,&debug,"Output debugging",NULL },
27 static struct WinHttpFuncs
29 WINBOOL (WINAPI *AddRequestHeaders)(HINTERNET,LPCWSTR,DWORD,DWORD);
30 WINBOOL (WINAPI *DetectAutoProxyConfigUrl)(DWORD,LPWSTR*);
31 WINBOOL (WINAPI *CheckPlatform)(void);
32 WINBOOL (WINAPI *CloseHandle)(HINTERNET);
33 HINTERNET (WINAPI *Connect)(HINTERNET,LPCWSTR,INTERNET_PORT,DWORD);
34 WINBOOL (WINAPI *CrackUrl)(LPCWSTR,DWORD,DWORD,LPURL_COMPONENTS);
35 WINBOOL (WINAPI *CreateUrl)(LPURL_COMPONENTS,DWORD,LPWSTR,LPDWORD);
36 WINBOOL (WINAPI *GetDefaultProxyConfiguration)(WINHTTP_PROXY_INFO*);
37 WINBOOL (WINAPI *GetIEProxyConfigForCurrentUser)(WINHTTP_CURRENT_USER_IE_PROXY_CONFIG*);
38 WINBOOL (WINAPI *GetProxyForUrl)(HINTERNET,LPCWSTR,WINHTTP_AUTOPROXY_OPTIONS*,WINHTTP_PROXY_INFO*);
39 HINTERNET (WINAPI *Open)(LPCWSTR,DWORD,LPCWSTR,LPCWSTR,DWORD);
40 HINTERNET (WINAPI *OpenRequest)(HINTERNET,LPCWSTR,LPCWSTR,LPCWSTR,LPCWSTR,LPCWSTR*,DWORD);
41 WINBOOL (WINAPI *QueryAuthParams)(HINTERNET,DWORD,LPVOID*);
42 WINBOOL (WINAPI *QueryAuthSchemes)(HINTERNET,LPDWORD,LPDWORD,LPDWORD);
43 WINBOOL (WINAPI *QueryDataAvailable)(HINTERNET,LPDWORD);
44 WINBOOL (WINAPI *QueryHeaders)(HINTERNET,DWORD,LPCWSTR,LPVOID,LPDWORD,LPDWORD);
45 WINBOOL (WINAPI *QueryOption)(HINTERNET,DWORD,LPVOID,LPDWORD);
46 WINBOOL (WINAPI *ReadData)(HINTERNET,LPVOID,DWORD,LPDWORD);
47 WINBOOL (WINAPI *ReceiveResponse)(HINTERNET,LPVOID);
48 WINBOOL (WINAPI *SendRequest)(HINTERNET,LPCWSTR,DWORD,LPVOID,DWORD,DWORD,DWORD_PTR);
49 WINBOOL (WINAPI *SetDefaultProxyConfiguration)(WINHTTP_PROXY_INFO*);
50 WINBOOL (WINAPI *SetCredentials)(HINTERNET,DWORD,DWORD,LPCWSTR,LPCWSTR,LPVOID);
51 WINBOOL (WINAPI *SetOption)(HINTERNET,DWORD,LPVOID,DWORD);
52 WINHTTP_STATUS_CALLBACK (WINAPI *SetStatusCallback)(HINTERNET,WINHTTP_STATUS_CALLBACK,DWORD,DWORD_PTR);
53 WINBOOL (WINAPI *SetTimeouts)(HINTERNET,int,int,int,int);
54 WINBOOL (WINAPI *TimeFromSystemTime)(CONST SYSTEMTIME *,LPWSTR);
55 WINBOOL (WINAPI *TimeToSystemTime)(LPCWSTR,SYSTEMTIME*);
56 WINBOOL (WINAPI *WriteData)(HINTERNET,LPCVOID,DWORD,LPDWORD);
59 static int plover_init_winhttp(void)
64 module=LoadLibraryA("winhttp.dll");
67 WinHttp.AddRequestHeaders=
68 (WINBOOL (WINAPI *)(HINTERNET,LPCWSTR,DWORD,DWORD))
69 GetProcAddress(module,"WinHttpAddRequestHeaders");
70 WinHttp.DetectAutoProxyConfigUrl=
71 (WINBOOL (WINAPI *)(DWORD,LPWSTR*))
72 GetProcAddress(module,"WinHttpDetectAutoProxyConfigUrl");
73 WinHttp.CheckPlatform=(WINBOOL (WINAPI *)(void))
74 GetProcAddress(module,"WinHttpCheckPlatform");
75 WinHttp.CloseHandle=(WINBOOL (WINAPI *)(HINTERNET))
76 GetProcAddress(module,"WinHttpCloseHandle");
78 (HINTERNET (WINAPI *)(HINTERNET,LPCWSTR,INTERNET_PORT,DWORD))
79 GetProcAddress(module,"WinHttpConnect");
80 WinHttp.CrackUrl=(WINBOOL (WINAPI *)(LPCWSTR,DWORD,DWORD,LPURL_COMPONENTS))
81 GetProcAddress(module,"WinHttpCrackUrl");
83 (WINBOOL (WINAPI *)(LPURL_COMPONENTS,DWORD,LPWSTR,LPDWORD))
84 GetProcAddress(module,"WinHttpCreateUrl");
85 WinHttp.GetDefaultProxyConfiguration=
86 (WINBOOL (WINAPI *)(WINHTTP_PROXY_INFO*))
87 GetProcAddress(module,"WinHttpGetDefaultProxyConfiguration");
88 WinHttp.GetIEProxyConfigForCurrentUser=
89 (WINBOOL (WINAPI *)(WINHTTP_CURRENT_USER_IE_PROXY_CONFIG*))
90 GetProcAddress(module,"WinHttpGetIEProxyConfigForCurrentUser");
91 WinHttp.GetProxyForUrl=
92 (WINBOOL (WINAPI *)(HINTERNET,LPCWSTR,WINHTTP_AUTOPROXY_OPTIONS*,WINHTTP_PROXY_INFO*))
93 GetProcAddress(module,"WinHttpGetProxyForUrl");
94 WinHttp.Open=(HINTERNET (WINAPI *)(LPCWSTR,DWORD,LPCWSTR,LPCWSTR,DWORD))
95 GetProcAddress(module,"WinHttpOpen");
97 (HINTERNET (WINAPI *)(HINTERNET,LPCWSTR,LPCWSTR,LPCWSTR,LPCWSTR,LPCWSTR*,DWORD))
98 GetProcAddress(module,"WinHttpOpenRequest");
99 WinHttp.QueryAuthParams=(WINBOOL (WINAPI *)(HINTERNET,DWORD,LPVOID*))
100 GetProcAddress(module,"WinHttpQueryAuthParams");
101 WinHttp.QueryAuthSchemes=
102 (WINBOOL (WINAPI *)(HINTERNET,LPDWORD,LPDWORD,LPDWORD))
103 GetProcAddress(module,"WinHttpQueryAuthSchemes");
104 WinHttp.QueryDataAvailable=(WINBOOL (WINAPI *)(HINTERNET,LPDWORD))
105 GetProcAddress(module,"WinHttpQueryDataAvailable");
106 WinHttp.QueryHeaders=
107 (WINBOOL (WINAPI *)(HINTERNET,DWORD,LPCWSTR,LPVOID,LPDWORD,LPDWORD))
108 GetProcAddress(module,"WinHttpQueryHeaders");
109 WinHttp.QueryOption=(WINBOOL (WINAPI *)(HINTERNET,DWORD,LPVOID,LPDWORD))
110 GetProcAddress(module,"WinHttpQueryOption");
111 WinHttp.ReadData=(WINBOOL (WINAPI *)(HINTERNET,LPVOID,DWORD,LPDWORD))
112 GetProcAddress(module,"WinHttpReadData");
113 WinHttp.ReceiveResponse=(WINBOOL (WINAPI *)(HINTERNET,LPVOID))
114 GetProcAddress(module,"WinHttpReceiveResponse");
116 (WINBOOL (WINAPI *)(HINTERNET,LPCWSTR,DWORD,LPVOID,DWORD,DWORD,DWORD_PTR))
117 GetProcAddress(module,"WinHttpSendRequest");
118 WinHttp.SetDefaultProxyConfiguration=
119 (WINBOOL (WINAPI *)(WINHTTP_PROXY_INFO*))
120 GetProcAddress(module,"WinHttpSetDefaultProxyConfiguration");
121 WinHttp.SetCredentials=
122 (WINBOOL (WINAPI *)(HINTERNET,DWORD,DWORD,LPCWSTR,LPCWSTR,LPVOID))
123 GetProcAddress(module,"WinHttpSetCredentials");
124 WinHttp.SetOption=(WINBOOL (WINAPI *)(HINTERNET,DWORD,LPVOID,DWORD))
125 GetProcAddress(module,"WinHttpSetOption");
126 WinHttp.SetStatusCallback=
127 (WINHTTP_STATUS_CALLBACK (WINAPI *)(HINTERNET,WINHTTP_STATUS_CALLBACK,DWORD,DWORD_PTR))
128 GetProcAddress(module,"WinHttpSetStatusCallback");
129 WinHttp.SetTimeouts=(WINBOOL (WINAPI *)(HINTERNET,int,int,int,int))
130 GetProcAddress(module,"WinHttpSetTimeouts");
131 WinHttp.TimeFromSystemTime=(WINBOOL (WINAPI *)(CONST SYSTEMTIME *,LPWSTR))
132 GetProcAddress(module,"WinHttpTimeFromSystemTime");
133 WinHttp.TimeToSystemTime=(WINBOOL (WINAPI *)(LPCWSTR,SYSTEMTIME*))
134 GetProcAddress(module,"WinHttpTimeToSystemTime");
135 WinHttp.WriteData=(WINBOOL (WINAPI *)(HINTERNET,LPCVOID,DWORD,LPDWORD))
136 GetProcAddress(module,"WinHttpWriteData");
137 if (!WinHttp.CrackUrl || !WinHttp.Open || !WinHttp.Connect ||
138 !WinHttp.OpenRequest || !WinHttp.SendRequest ||
139 !WinHttp.ReceiveResponse || !WinHttp.QueryDataAvailable ||
140 !WinHttp.ReadData || !WinHttp.CloseHandle)
150 * This will find ${PREFIX}/${file} if it exists, but it may also
151 * find ${PREFIX}/.../${file} if ${PREFIX}/${file} does not exist.
152 * This seems unlikely and won't do any harm should it occur.
155 gchar *find_prefixed_file(const char *file)
160 struct razor_set *set;
161 struct razor_error *error=NULL;
162 struct razor_package *package;
163 struct razor_package_iterator *pi;
164 struct razor_file_iterator *fi;
167 install_root=getenv("RAZOR_ROOT");
170 set=razor_root_open_read_only(install_root,&error);
173 pi=razor_package_iterator_create(set);
174 while (razor_package_iterator_next(pi,&package,RAZOR_DETAIL_LAST))
176 fi=razor_file_iterator_create(set,package,0);
177 while (!retval && razor_file_iterator_next(fi,&name))
180 if (i>0 && name[i-1]=='/' && !strcmp(name+i,file))
182 if (!retval || strlen(retval)>strlen(name))
185 retval=g_strdup(name);
189 razor_file_iterator_destroy(fi);
191 razor_package_iterator_destroy(pi);
192 razor_set_unref(set);
195 razor_error_free(error);
199 static HCERTSTORE plover_p12_import(const char *file,const wchar_t *password)
206 s=g_build_path("/","etc","pki",file,NULL);
207 path=find_prefixed_file(s);
210 g_printerr("%s: Not installed\n",s);
215 if (!g_file_get_contents(path,&p12,&len,&error))
217 g_printerr("%s: %s\n",path,error->message);
223 pfx.pbData=(BYTE *)p12;
225 store=PFXImportCertStore(&pfx,password,PKCS12_NO_PERSIST_KEY);
227 g_printerr("PFXImportCertStore failed. Err: %lu\n",GetLastError());
232 static const CERT_CONTEXT *plover_get_client_certificate(HCERTSTORE store)
234 const CERT_CONTEXT *iter,*cert;
236 iter=CertEnumCertificatesInStore(store,NULL);
240 cert=CertDuplicateCertificateContext(iter);
241 iter=CertEnumCertificatesInStore(store,iter);
246 void CALLBACK plover_status_callback(HINTERNET handle,DWORD_PTR context,
247 DWORD status,LPVOID status_information,DWORD status_information_length)
249 g_printerr("CB status 0x%lX",status);
250 if (status==WINHTTP_CALLBACK_STATUS_SECURE_FAILURE)
251 g_printerr(", flag 0x%lX",*(DWORD *)status_information);
255 int fetch(HINTERNET session,HCERTSTORE store,const char *url)
257 URL_COMPONENTS components={0};
258 HINTERNET connection,request;
259 DWORD len,nb,options;
263 gchar *hostname,*path;
264 const CERT_CONTEXT *client_cert;
265 components.dwStructSize=sizeof(components);
266 components.dwSchemeLength=(DWORD)-1;
267 components.dwHostNameLength=(DWORD)-1;
268 components.dwUserNameLength=(DWORD)-1;
269 components.dwPasswordLength=(DWORD)-1;
270 components.dwUrlPathLength=(DWORD)-1;
271 ws=g_utf8_to_utf16(url,-1,NULL,&ws_len,NULL);
272 if (!ws || !WinHttp.CrackUrl(ws,ws_len,0,&components))
274 g_printerr("%s: Invalid or unsupported URL\n",url);
277 /* ICU_REJECT_USERPWD is not supported under Windows XP */
278 if (components.dwUserNameLength || components.dwPasswordLength)
280 g_printerr("%s: Credentials not supported\n",url);
283 hostname=g_utf16_to_utf8(components.lpszHostName,
284 components.dwHostNameLength,NULL,NULL,NULL);
285 path=g_utf16_to_utf8(components.lpszUrlPath,components.dwUrlPathLength,NULL,
288 ws=g_utf8_to_utf16(hostname,-1,NULL,NULL,NULL);
289 connection=WinHttp.Connect(session,ws,
290 components.nPort?components.nPort:INTERNET_DEFAULT_PORT,0);
294 ws=g_utf8_to_utf16(path,-1,NULL,NULL,NULL);
295 request=WinHttp.OpenRequest(connection,L"GET",ws,NULL,
296 WINHTTP_NO_REFERER,WINHTTP_DEFAULT_ACCEPT_TYPES,
297 components.nScheme==INTERNET_SCHEME_HTTPS?WINHTTP_FLAG_SECURE:0);
302 (void)WinHttp.SetStatusCallback(request,plover_status_callback,
303 WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS,0);
304 if (components.nScheme==INTERNET_SCHEME_HTTPS && WinHttp.SetOption)
306 options=SECURITY_FLAG_IGNORE_UNKNOWN_CA;
307 (void)WinHttp.SetOption(request,WINHTTP_OPTION_SECURITY_FLAGS,
308 &options,sizeof(options));
309 client_cert=plover_get_client_certificate(store);
312 if (!WinHttp.SetOption(request,
313 WINHTTP_OPTION_CLIENT_CERT_CONTEXT,(void *)client_cert,
314 sizeof(*client_cert)))
315 g_printerr("Failed to set client certificate (%lu)\n",
319 g_printerr("No client certificate found\n");
321 if (!WinHttp.SendRequest(request,WINHTTP_NO_ADDITIONAL_HEADERS,
322 0,WINHTTP_NO_REQUEST_DATA,0,0,0))
323 g_printerr("Failed to send request (%lu)\n",GetLastError());
324 else if (!WinHttp.ReceiveResponse(request,NULL))
325 g_printerr("Failed to receive response (%lu)\n",GetLastError());
331 if (!WinHttp.QueryDataAvailable(request,&len))
333 "Error %lu in WinHttpQueryDataAvailable.\n",
334 (unsigned long)GetLastError());
335 buffer=calloc(len+1,1);
340 if (!WinHttp.ReadData(request,(void *)buffer,len,&nb))
341 g_printerr("Error %lu in WinHttpReadData.\n",
342 (unsigned long)GetLastError());
344 printf("%s\n",buffer);
349 WinHttp.CloseHandle(request);
352 g_printerr("Failed to open request for %s (%lu)\n",path,
354 WinHttp.CloseHandle(connection);
357 g_printerr("Failed to open connection to %s\n",hostname);
363 int main(int argc,char **argv)
366 GOptionContext *context;
370 context=g_option_context_new("URL - fetch a URL");
371 g_option_context_add_main_entries(context,entries,NULL);
372 if (!g_option_context_parse(context,&argc,&argv,&error))
374 g_printerr("Option parsing failed: %s\n",error->message);
379 g_printerr("%s\n",g_option_context_get_help(context,TRUE,NULL));
382 if (plover_init_winhttp())
384 g_printerr("HTTP is not supported on this machine\n");
387 store=plover_p12_import("system.p12",L"xyzzy-ylem");
390 ws=g_utf8_to_utf16(PACKAGE_NAME "/" PACKAGE_VERSION,-1,NULL,NULL,NULL);
391 session=WinHttp.Open(ws,WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
392 WINHTTP_NO_PROXY_NAME,WINHTTP_NO_PROXY_BYPASS,0);
396 g_printerr("Failed to open WinHttp session\n");
399 if (fetch(session,store,argv[1]))
401 WinHttp.CloseHandle(session);
402 CertCloseStore(store,CERT_CLOSE_STORE_FORCE_FLAG);
405 #else /* !HAVE_WINHTTP_H */
408 g_printerr("HTTP is not supported on this machine\n");
411 #endif /* HAVE_WINHTTP_H */