Support parallel installations. The idea is that for CAD screener, we want
to be able to install this on the same machine as a standard AVOT setup
(most notably for John's laptop). To allow for the possibility of a second
application that might have the same requirements, we add the concept of
vendor-specific distributions. Thus we can have one distribution for CAD
screener and one for The Next Big Thing. It doesn't seem trivial to have
both CAD screener and AVOT under the same vendor tag so we'll have to have
AVOT under "City Occupational" and CAD screener under "City Occupational Ltd"
or some such kludge.
Most of this is done although we are very short of test cases (in particular
we don't test that it's actually possible to install CAD screener in parallel
with AVOT or to update either of them once installed, which is fundamental).
We also have a lot of baggage left over, including an intercept of razor_set.
The problem that this was introduced to debug has been fixed but it looks
like there are a number of memory leaks which it might be useful to help
track down so it has been left in place for now.
There is still a lot of confusion in plover between path-based and URI-based
API. We should review the API, decide what we want and have a general clear up.
There is also confusion as to the purpose of RAZOR_ROOT (and meaning; path or
URI). This is not used at all in librazor (although it is used in razor.exe).
Ideally we shouldn't use it in plover or plover-gtk either although again, we
might want to support it or an equivalent in (some of) the various executables.
Work that would still to nice to do for CAD screener:
- uninstall (ideally as an installed program that hooks into Add/Remove programs
but even re-running the installer would be acceptable).
- xz support (smaller packages).
- repomd.xml and xml:base (would be needed for an Internet installer).
- graphical installer.
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 */