1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/app-manager/fetch.c Mon Jan 30 13:35:28 2012 +0000
1.3 @@ -0,0 +1,411 @@
1.4 +/*
1.5 + * A program to explore http support on MS-Windows.
1.6 + */
1.7 +
1.8 +#include "config.h"
1.9 +#include <stdlib.h>
1.10 +#include <stdio.h>
1.11 +#include <glib.h>
1.12 +#include <razor.h>
1.13 +#if HAVE_WINHTTP_H
1.14 +#include <windows.h>
1.15 +#include <winhttp.h>
1.16 +#include <wincrypt.h>
1.17 +
1.18 +#ifndef PKCS12_NO_PERSIST_KEY
1.19 +#define PKCS12_NO_PERSIST_KEY 0x00008000
1.20 +#endif
1.21 +
1.22 +static gboolean debug=FALSE;
1.23 +
1.24 +static GOptionEntry entries[] =
1.25 +{
1.26 + { "debug",'d',0,G_OPTION_ARG_NONE,&debug,"Output debugging",NULL },
1.27 + { NULL }
1.28 +};
1.29 +
1.30 +static struct WinHttpFuncs
1.31 +{
1.32 + WINBOOL (WINAPI *AddRequestHeaders)(HINTERNET,LPCWSTR,DWORD,DWORD);
1.33 + WINBOOL (WINAPI *DetectAutoProxyConfigUrl)(DWORD,LPWSTR*);
1.34 + WINBOOL (WINAPI *CheckPlatform)(void);
1.35 + WINBOOL (WINAPI *CloseHandle)(HINTERNET);
1.36 + HINTERNET (WINAPI *Connect)(HINTERNET,LPCWSTR,INTERNET_PORT,DWORD);
1.37 + WINBOOL (WINAPI *CrackUrl)(LPCWSTR,DWORD,DWORD,LPURL_COMPONENTS);
1.38 + WINBOOL (WINAPI *CreateUrl)(LPURL_COMPONENTS,DWORD,LPWSTR,LPDWORD);
1.39 + WINBOOL (WINAPI *GetDefaultProxyConfiguration)(WINHTTP_PROXY_INFO*);
1.40 + WINBOOL (WINAPI *GetIEProxyConfigForCurrentUser)(WINHTTP_CURRENT_USER_IE_PROXY_CONFIG*);
1.41 + WINBOOL (WINAPI *GetProxyForUrl)(HINTERNET,LPCWSTR,WINHTTP_AUTOPROXY_OPTIONS*,WINHTTP_PROXY_INFO*);
1.42 + HINTERNET (WINAPI *Open)(LPCWSTR,DWORD,LPCWSTR,LPCWSTR,DWORD);
1.43 + HINTERNET (WINAPI *OpenRequest)(HINTERNET,LPCWSTR,LPCWSTR,LPCWSTR,LPCWSTR,LPCWSTR*,DWORD);
1.44 + WINBOOL (WINAPI *QueryAuthParams)(HINTERNET,DWORD,LPVOID*);
1.45 + WINBOOL (WINAPI *QueryAuthSchemes)(HINTERNET,LPDWORD,LPDWORD,LPDWORD);
1.46 + WINBOOL (WINAPI *QueryDataAvailable)(HINTERNET,LPDWORD);
1.47 + WINBOOL (WINAPI *QueryHeaders)(HINTERNET,DWORD,LPCWSTR,LPVOID,LPDWORD,LPDWORD);
1.48 + WINBOOL (WINAPI *QueryOption)(HINTERNET,DWORD,LPVOID,LPDWORD);
1.49 + WINBOOL (WINAPI *ReadData)(HINTERNET,LPVOID,DWORD,LPDWORD);
1.50 + WINBOOL (WINAPI *ReceiveResponse)(HINTERNET,LPVOID);
1.51 + WINBOOL (WINAPI *SendRequest)(HINTERNET,LPCWSTR,DWORD,LPVOID,DWORD,DWORD,DWORD_PTR);
1.52 + WINBOOL (WINAPI *SetDefaultProxyConfiguration)(WINHTTP_PROXY_INFO*);
1.53 + WINBOOL (WINAPI *SetCredentials)(HINTERNET,DWORD,DWORD,LPCWSTR,LPCWSTR,LPVOID);
1.54 + WINBOOL (WINAPI *SetOption)(HINTERNET,DWORD,LPVOID,DWORD);
1.55 + WINHTTP_STATUS_CALLBACK (WINAPI *SetStatusCallback)(HINTERNET,WINHTTP_STATUS_CALLBACK,DWORD,DWORD_PTR);
1.56 + WINBOOL (WINAPI *SetTimeouts)(HINTERNET,int,int,int,int);
1.57 + WINBOOL (WINAPI *TimeFromSystemTime)(CONST SYSTEMTIME *,LPWSTR);
1.58 + WINBOOL (WINAPI *TimeToSystemTime)(LPCWSTR,SYSTEMTIME*);
1.59 + WINBOOL (WINAPI *WriteData)(HINTERNET,LPCVOID,DWORD,LPDWORD);
1.60 +} WinHttp;
1.61 +
1.62 +static int plover_init_winhttp(void)
1.63 +{
1.64 + HMODULE module;
1.65 + if (WinHttp.Open)
1.66 + return 0;
1.67 + module=LoadLibraryA("winhttp.dll");
1.68 + if (!module)
1.69 + return -1;
1.70 + WinHttp.AddRequestHeaders=
1.71 + (WINBOOL (WINAPI *)(HINTERNET,LPCWSTR,DWORD,DWORD))
1.72 + GetProcAddress(module,"WinHttpAddRequestHeaders");
1.73 + WinHttp.DetectAutoProxyConfigUrl=
1.74 + (WINBOOL (WINAPI *)(DWORD,LPWSTR*))
1.75 + GetProcAddress(module,"WinHttpDetectAutoProxyConfigUrl");
1.76 + WinHttp.CheckPlatform=(WINBOOL (WINAPI *)(void))
1.77 + GetProcAddress(module,"WinHttpCheckPlatform");
1.78 + WinHttp.CloseHandle=(WINBOOL (WINAPI *)(HINTERNET))
1.79 + GetProcAddress(module,"WinHttpCloseHandle");
1.80 + WinHttp.Connect=
1.81 + (HINTERNET (WINAPI *)(HINTERNET,LPCWSTR,INTERNET_PORT,DWORD))
1.82 + GetProcAddress(module,"WinHttpConnect");
1.83 + WinHttp.CrackUrl=(WINBOOL (WINAPI *)(LPCWSTR,DWORD,DWORD,LPURL_COMPONENTS))
1.84 + GetProcAddress(module,"WinHttpCrackUrl");
1.85 + WinHttp.CreateUrl=
1.86 + (WINBOOL (WINAPI *)(LPURL_COMPONENTS,DWORD,LPWSTR,LPDWORD))
1.87 + GetProcAddress(module,"WinHttpCreateUrl");
1.88 + WinHttp.GetDefaultProxyConfiguration=
1.89 + (WINBOOL (WINAPI *)(WINHTTP_PROXY_INFO*))
1.90 + GetProcAddress(module,"WinHttpGetDefaultProxyConfiguration");
1.91 + WinHttp.GetIEProxyConfigForCurrentUser=
1.92 + (WINBOOL (WINAPI *)(WINHTTP_CURRENT_USER_IE_PROXY_CONFIG*))
1.93 + GetProcAddress(module,"WinHttpGetIEProxyConfigForCurrentUser");
1.94 + WinHttp.GetProxyForUrl=
1.95 + (WINBOOL (WINAPI *)(HINTERNET,LPCWSTR,WINHTTP_AUTOPROXY_OPTIONS*,WINHTTP_PROXY_INFO*))
1.96 + GetProcAddress(module,"WinHttpGetProxyForUrl");
1.97 + WinHttp.Open=(HINTERNET (WINAPI *)(LPCWSTR,DWORD,LPCWSTR,LPCWSTR,DWORD))
1.98 + GetProcAddress(module,"WinHttpOpen");
1.99 + WinHttp.OpenRequest=
1.100 + (HINTERNET (WINAPI *)(HINTERNET,LPCWSTR,LPCWSTR,LPCWSTR,LPCWSTR,LPCWSTR*,DWORD))
1.101 + GetProcAddress(module,"WinHttpOpenRequest");
1.102 + WinHttp.QueryAuthParams=(WINBOOL (WINAPI *)(HINTERNET,DWORD,LPVOID*))
1.103 + GetProcAddress(module,"WinHttpQueryAuthParams");
1.104 + WinHttp.QueryAuthSchemes=
1.105 + (WINBOOL (WINAPI *)(HINTERNET,LPDWORD,LPDWORD,LPDWORD))
1.106 + GetProcAddress(module,"WinHttpQueryAuthSchemes");
1.107 + WinHttp.QueryDataAvailable=(WINBOOL (WINAPI *)(HINTERNET,LPDWORD))
1.108 + GetProcAddress(module,"WinHttpQueryDataAvailable");
1.109 + WinHttp.QueryHeaders=
1.110 + (WINBOOL (WINAPI *)(HINTERNET,DWORD,LPCWSTR,LPVOID,LPDWORD,LPDWORD))
1.111 + GetProcAddress(module,"WinHttpQueryHeaders");
1.112 + WinHttp.QueryOption=(WINBOOL (WINAPI *)(HINTERNET,DWORD,LPVOID,LPDWORD))
1.113 + GetProcAddress(module,"WinHttpQueryOption");
1.114 + WinHttp.ReadData=(WINBOOL (WINAPI *)(HINTERNET,LPVOID,DWORD,LPDWORD))
1.115 + GetProcAddress(module,"WinHttpReadData");
1.116 + WinHttp.ReceiveResponse=(WINBOOL (WINAPI *)(HINTERNET,LPVOID))
1.117 + GetProcAddress(module,"WinHttpReceiveResponse");
1.118 + WinHttp.SendRequest=
1.119 + (WINBOOL (WINAPI *)(HINTERNET,LPCWSTR,DWORD,LPVOID,DWORD,DWORD,DWORD_PTR))
1.120 + GetProcAddress(module,"WinHttpSendRequest");
1.121 + WinHttp.SetDefaultProxyConfiguration=
1.122 + (WINBOOL (WINAPI *)(WINHTTP_PROXY_INFO*))
1.123 + GetProcAddress(module,"WinHttpSetDefaultProxyConfiguration");
1.124 + WinHttp.SetCredentials=
1.125 + (WINBOOL (WINAPI *)(HINTERNET,DWORD,DWORD,LPCWSTR,LPCWSTR,LPVOID))
1.126 + GetProcAddress(module,"WinHttpSetCredentials");
1.127 + WinHttp.SetOption=(WINBOOL (WINAPI *)(HINTERNET,DWORD,LPVOID,DWORD))
1.128 + GetProcAddress(module,"WinHttpSetOption");
1.129 + WinHttp.SetStatusCallback=
1.130 + (WINHTTP_STATUS_CALLBACK (WINAPI *)(HINTERNET,WINHTTP_STATUS_CALLBACK,DWORD,DWORD_PTR))
1.131 + GetProcAddress(module,"WinHttpSetStatusCallback");
1.132 + WinHttp.SetTimeouts=(WINBOOL (WINAPI *)(HINTERNET,int,int,int,int))
1.133 + GetProcAddress(module,"WinHttpSetTimeouts");
1.134 + WinHttp.TimeFromSystemTime=(WINBOOL (WINAPI *)(CONST SYSTEMTIME *,LPWSTR))
1.135 + GetProcAddress(module,"WinHttpTimeFromSystemTime");
1.136 + WinHttp.TimeToSystemTime=(WINBOOL (WINAPI *)(LPCWSTR,SYSTEMTIME*))
1.137 + GetProcAddress(module,"WinHttpTimeToSystemTime");
1.138 + WinHttp.WriteData=(WINBOOL (WINAPI *)(HINTERNET,LPCVOID,DWORD,LPDWORD))
1.139 + GetProcAddress(module,"WinHttpWriteData");
1.140 + if (!WinHttp.CrackUrl || !WinHttp.Open || !WinHttp.Connect ||
1.141 + !WinHttp.OpenRequest || !WinHttp.SendRequest ||
1.142 + !WinHttp.ReceiveResponse || !WinHttp.QueryDataAvailable ||
1.143 + !WinHttp.ReadData || !WinHttp.CloseHandle)
1.144 + {
1.145 + FreeLibrary(module);
1.146 + WinHttp.Open=NULL;
1.147 + return -1;
1.148 + }
1.149 + return 0;
1.150 +}
1.151 +
1.152 +/*
1.153 + * This will find ${PREFIX}/${file} if it exists, but it may also
1.154 + * find ${PREFIX}/.../${file} if ${PREFIX}/${file} does not exist.
1.155 + * This seems unlikely and won't do any harm should it occur.
1.156 + */
1.157 +
1.158 +gchar *find_prefixed_file(const char *file)
1.159 +{
1.160 + int i,len;
1.161 + const char *name;
1.162 + char *install_root;
1.163 + struct razor_set *set;
1.164 + struct razor_atomic *atomic;
1.165 + struct razor_package *package;
1.166 + struct razor_package_iterator *pi;
1.167 + struct razor_file_iterator *fi;
1.168 + gchar *retval=NULL;
1.169 + len=strlen(file);
1.170 + install_root=getenv("RAZOR_ROOT");
1.171 + if (!install_root)
1.172 + install_root="";
1.173 + atomic=razor_atomic_open("Query packages");
1.174 + set=razor_root_open_read_only(install_root,atomic);
1.175 + if (set)
1.176 + {
1.177 + pi=razor_package_iterator_create(set);
1.178 + while (razor_package_iterator_next(pi,&package,RAZOR_DETAIL_LAST))
1.179 + {
1.180 + fi=razor_file_iterator_create(set,package,0);
1.181 + while (!retval && razor_file_iterator_next(fi,&name))
1.182 + {
1.183 + i=strlen(name)-len;
1.184 + if (i>0 && name[i-1]=='/' && !strcmp(name+i,file))
1.185 + {
1.186 + if (!retval || strlen(retval)>strlen(name))
1.187 + {
1.188 + g_free(retval);
1.189 + retval=g_strdup(name);
1.190 + }
1.191 + }
1.192 + }
1.193 + razor_file_iterator_destroy(fi);
1.194 + }
1.195 + razor_package_iterator_destroy(pi);
1.196 + razor_set_unref(set);
1.197 + }
1.198 + razor_atomic_destroy(atomic);
1.199 + return retval;
1.200 +}
1.201 +
1.202 +static HCERTSTORE plover_p12_import(const char *file,const wchar_t *password)
1.203 +{
1.204 + GError *error=NULL;
1.205 + gchar *p12,*path,*s;
1.206 + gsize len;
1.207 + CRYPT_DATA_BLOB pfx;
1.208 + HCERTSTORE store;
1.209 + s=g_build_path("/","etc","pki",file,NULL);
1.210 + path=find_prefixed_file(s);
1.211 + if (!path)
1.212 + {
1.213 + g_printerr("%s: Not installed\n",s);
1.214 + g_free(s);
1.215 + return NULL;
1.216 + }
1.217 + g_free(s);
1.218 + if (!g_file_get_contents(path,&p12,&len,&error))
1.219 + {
1.220 + g_printerr("%s: %s\n",path,error->message);
1.221 + g_free(path);
1.222 + g_error_free(error);
1.223 + return NULL;
1.224 + }
1.225 + g_free(path);
1.226 + pfx.pbData=(BYTE *)p12;
1.227 + pfx.cbData=len;
1.228 + store=PFXImportCertStore(&pfx,password,PKCS12_NO_PERSIST_KEY);
1.229 + if (!store)
1.230 + g_printerr("PFXImportCertStore failed. Err: %lu\n",GetLastError());
1.231 + g_free(p12);
1.232 + return store;
1.233 +}
1.234 +
1.235 +static const CERT_CONTEXT *plover_get_client_certificate(HCERTSTORE store)
1.236 +{
1.237 + const CERT_CONTEXT *iter,*cert;
1.238 + cert=NULL;
1.239 + iter=CertEnumCertificatesInStore(store,NULL);
1.240 + while(iter)
1.241 + {
1.242 + if (!cert)
1.243 + cert=CertDuplicateCertificateContext(iter);
1.244 + iter=CertEnumCertificatesInStore(store,iter);
1.245 + }
1.246 + return cert;
1.247 +}
1.248 +
1.249 +void CALLBACK plover_status_callback(HINTERNET handle,DWORD_PTR context,
1.250 + DWORD status,LPVOID status_information,DWORD status_information_length)
1.251 +{
1.252 + g_printerr("CB status 0x%lX",status);
1.253 + if (status==WINHTTP_CALLBACK_STATUS_SECURE_FAILURE)
1.254 + g_printerr(", flag 0x%lX",*(DWORD *)status_information);
1.255 + g_printerr("\n");
1.256 +}
1.257 +
1.258 +int fetch(HINTERNET session,HCERTSTORE store,const char *url)
1.259 +{
1.260 + URL_COMPONENTS components={0};
1.261 + HINTERNET connection,request;
1.262 + DWORD len,nb,options;
1.263 + char *buffer;
1.264 + wchar_t *ws;
1.265 + glong ws_len;
1.266 + gchar *hostname,*path;
1.267 + const CERT_CONTEXT *client_cert;
1.268 + components.dwStructSize=sizeof(components);
1.269 + components.dwSchemeLength=(DWORD)-1;
1.270 + components.dwHostNameLength=(DWORD)-1;
1.271 + components.dwUserNameLength=(DWORD)-1;
1.272 + components.dwPasswordLength=(DWORD)-1;
1.273 + components.dwUrlPathLength=(DWORD)-1;
1.274 + ws=g_utf8_to_utf16(url,-1,NULL,&ws_len,NULL);
1.275 + if (!ws || !WinHttp.CrackUrl(ws,ws_len,0,&components))
1.276 + {
1.277 + g_printerr("%s: Invalid or unsupported URL\n",url);
1.278 + return -1;
1.279 + }
1.280 + /* ICU_REJECT_USERPWD is not supported under Windows XP */
1.281 + if (components.dwUserNameLength || components.dwPasswordLength)
1.282 + {
1.283 + g_printerr("%s: Credentials not supported\n",url);
1.284 + return -1;
1.285 + }
1.286 + hostname=g_utf16_to_utf8(components.lpszHostName,
1.287 + components.dwHostNameLength,NULL,NULL,NULL);
1.288 + path=g_utf16_to_utf8(components.lpszUrlPath,components.dwUrlPathLength,NULL,
1.289 + NULL,NULL);
1.290 + g_free(ws);
1.291 + ws=g_utf8_to_utf16(hostname,-1,NULL,NULL,NULL);
1.292 + connection=WinHttp.Connect(session,ws,
1.293 + components.nPort?components.nPort:INTERNET_DEFAULT_PORT,0);
1.294 + g_free(ws);
1.295 + if (connection)
1.296 + {
1.297 + ws=g_utf8_to_utf16(path,-1,NULL,NULL,NULL);
1.298 + request=WinHttp.OpenRequest(connection,L"GET",ws,NULL,
1.299 + WINHTTP_NO_REFERER,WINHTTP_DEFAULT_ACCEPT_TYPES,
1.300 + components.nScheme==INTERNET_SCHEME_HTTPS?WINHTTP_FLAG_SECURE:0);
1.301 + g_free(ws);
1.302 + if (request)
1.303 + {
1.304 + if (debug)
1.305 + (void)WinHttp.SetStatusCallback(request,plover_status_callback,
1.306 + WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS,0);
1.307 + if (components.nScheme==INTERNET_SCHEME_HTTPS && WinHttp.SetOption)
1.308 + {
1.309 + options=SECURITY_FLAG_IGNORE_UNKNOWN_CA;
1.310 + (void)WinHttp.SetOption(request,WINHTTP_OPTION_SECURITY_FLAGS,
1.311 + &options,sizeof(options));
1.312 + client_cert=plover_get_client_certificate(store);
1.313 + if (client_cert)
1.314 + {
1.315 + if (!WinHttp.SetOption(request,
1.316 + WINHTTP_OPTION_CLIENT_CERT_CONTEXT,(void *)client_cert,
1.317 + sizeof(*client_cert)))
1.318 + g_printerr("Failed to set client certificate (%lu)\n",
1.319 + GetLastError());
1.320 + }
1.321 + else
1.322 + g_printerr("No client certificate found\n");
1.323 + }
1.324 + if (!WinHttp.SendRequest(request,WINHTTP_NO_ADDITIONAL_HEADERS,
1.325 + 0,WINHTTP_NO_REQUEST_DATA,0,0,0))
1.326 + g_printerr("Failed to send request (%lu)\n",GetLastError());
1.327 + else if (!WinHttp.ReceiveResponse(request,NULL))
1.328 + g_printerr("Failed to receive response (%lu)\n",GetLastError());
1.329 + else
1.330 + {
1.331 + do
1.332 + {
1.333 + len=0;
1.334 + if (!WinHttp.QueryDataAvailable(request,&len))
1.335 + g_printerr(
1.336 + "Error %lu in WinHttpQueryDataAvailable.\n",
1.337 + (unsigned long)GetLastError());
1.338 + buffer=calloc(len+1,1);
1.339 + if (!buffer)
1.340 + break;
1.341 + else
1.342 + {
1.343 + if (!WinHttp.ReadData(request,(void *)buffer,len,&nb))
1.344 + g_printerr("Error %lu in WinHttpReadData.\n",
1.345 + (unsigned long)GetLastError());
1.346 + else
1.347 + printf("%s\n",buffer);
1.348 + free(buffer);
1.349 + }
1.350 + } while (len>0);
1.351 + }
1.352 + WinHttp.CloseHandle(request);
1.353 + }
1.354 + else
1.355 + g_printerr("Failed to open request for %s (%lu)\n",path,
1.356 + GetLastError());
1.357 + WinHttp.CloseHandle(connection);
1.358 + }
1.359 + else
1.360 + g_printerr("Failed to open connection to %s\n",hostname);
1.361 + g_free(hostname);
1.362 + g_free(path);
1.363 + return 0;
1.364 +}
1.365 +
1.366 +int main(int argc,char **argv)
1.367 +{
1.368 + GError *error=NULL;
1.369 + GOptionContext *context;
1.370 + HCERTSTORE store;
1.371 + HINTERNET session;
1.372 + wchar_t *ws;
1.373 + context=g_option_context_new("URL - fetch a URL");
1.374 + g_option_context_add_main_entries(context,entries,NULL);
1.375 + if (!g_option_context_parse(context,&argc,&argv,&error))
1.376 + {
1.377 + g_printerr("Option parsing failed: %s\n",error->message);
1.378 + exit(1);
1.379 + }
1.380 + if (argc!=2)
1.381 + {
1.382 + g_printerr("%s\n",g_option_context_get_help(context,TRUE,NULL));
1.383 + exit(1);
1.384 + }
1.385 + if (plover_init_winhttp())
1.386 + {
1.387 + g_printerr("HTTP is not supported on this machine\n");
1.388 + exit(1);
1.389 + }
1.390 + store=plover_p12_import("system.p12",L"xyzzy-ylem");
1.391 + if (!store)
1.392 + exit(1);
1.393 + ws=g_utf8_to_utf16(PACKAGE_NAME "/" PACKAGE_VERSION,-1,NULL,NULL,NULL);
1.394 + session=WinHttp.Open(ws,WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
1.395 + WINHTTP_NO_PROXY_NAME,WINHTTP_NO_PROXY_BYPASS,0);
1.396 + free(ws);
1.397 + if (!session)
1.398 + {
1.399 + g_printerr("Failed to open WinHttp session\n");
1.400 + exit(1);
1.401 + }
1.402 + if (fetch(session,store,argv[1]))
1.403 + exit(1);
1.404 + WinHttp.CloseHandle(session);
1.405 + CertCloseStore(store,CERT_CLOSE_STORE_FORCE_FLAG);
1.406 + exit(0);
1.407 +}
1.408 +#else /* !HAVE_WINHTTP_H */
1.409 +main()
1.410 +{
1.411 + g_printerr("HTTP is not supported on this machine\n");
1.412 + exit(1);
1.413 +}
1.414 +#endif /* HAVE_WINHTTP_H */