8a6b7f8d8494fea7b12b8c7a0265b611a74911ae
[reactos.git] / dll / win32 / urlmon / internet.c
1 /*
2 * Copyright 2005 Jacek Caban
3 * Copyright 2011 Thomas Mullaly for CodeWeavers
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 */
19
20 #include "urlmon_main.h"
21
22 static const WCHAR feature_control_keyW[] =
23 {'S','o','f','t','w','a','r','e','\\',
24 'M','i','c','r','o','s','o','f','t','\\',
25 'I','n','t','e','r','n','e','t',' ','E','x','p','l','o','r','e','r','\\',
26 'M','a','i','n','\\',
27 'F','e','a','t','u','r','e','C','o','n','t','r','o','l',0};
28
29 static const WCHAR feature_object_cachingW[] =
30 {'F','E','A','T','U','R','E','_','O','B','J','E','C','T','_','C','A','C','H','I','N','G',0};
31 static const WCHAR feature_zone_elevationW[] =
32 {'F','E','A','T','U','R','E','_','Z','O','N','E','_','E','L','E','V','A','T','I','O','N',0};
33 static const WCHAR feature_mime_handlingW[] =
34 {'F','E','A','T','U','R','E','_','M','I','M','E','_','H','A','N','D','L','I','N','G',0};
35 static const WCHAR feature_mime_sniffingW[] =
36 {'F','E','A','T','U','R','E','_','M','I','M','E','_','S','N','I','F','F','I','N','G',0};
37 static const WCHAR feature_window_restrictionsW[] =
38 {'F','E','A','T','U','R','E','_','W','I','N','D','O','W','_','R','E','S','T','R','I','C','T','I','O','N','S',0};
39 static const WCHAR feature_weboc_popupmanagementW[] =
40 {'F','E','A','T','U','R','E','_','W','E','B','O','C','_','P','O','P','U','P','M','A','N','A','G','E','M','E','N','T',0};
41 static const WCHAR feature_behaviorsW[] =
42 {'F','E','A','T','U','R','E','_','B','E','H','A','V','I','O','R','S',0};
43 static const WCHAR feature_disable_mk_protocolW[] =
44 {'F','E','A','T','U','R','E','_','D','I','S','A','B','L','E','_','M','K','_','P','R','O','T','O','C','O','L',0};
45 static const WCHAR feature_localmachine_lockdownW[] =
46 {'F','E','A','T','U','R','E','_','L','O','C','A','L','M','A','C','H','I','N','E','_','L','O','C','K','D','O','W','N',0};
47 static const WCHAR feature_securitybandW[] =
48 {'F','E','A','T','U','R','E','_','S','E','C','U','R','I','T','Y','B','A','N','D',0};
49 static const WCHAR feature_restrict_activexinstallW[] =
50 {'F','E','A','T','U','R','E','_','R','E','S','T','R','I','C','T','_','A','C','T','I','V','E','X','I','N','S','T','A','L','L',0};
51 static const WCHAR feature_validate_navigate_urlW[] =
52 {'F','E','A','T','U','R','E','_','V','A','L','I','D','A','T','E','_','N','A','V','I','G','A','T','E','_','U','R','L',0};
53 static const WCHAR feature_restrict_filedownloadW[] =
54 {'F','E','A','T','U','R','E','_','R','E','S','T','R','I','C','T','_','F','I','L','E','D','O','W','N','L','O','A','D',0};
55 static const WCHAR feature_addon_managementW[] =
56 {'F','E','A','T','U','R','E','_','A','D','D','O','N','_','M','A','N','A','G','E','M','E','N','T',0};
57 static const WCHAR feature_protocol_lockdownW[] =
58 {'F','E','A','T','U','R','E','_','P','R','O','T','O','C','O','L','_','L','O','C','K','D','O','W','N',0};
59 static const WCHAR feature_http_username_password_disableW[] =
60 {'F','E','A','T','U','R','E','_','H','T','T','P','_','U','S','E','R','N','A','M','E','_',
61 'P','A','S','S','W','O','R','D','_','D','I','S','A','B','L','E',0};
62 static const WCHAR feature_safe_bindtoobjectW[] =
63 {'F','E','A','T','U','R','E','_','S','A','F','E','_','B','I','N','D','T','O','O','B','J','E','C','T',0};
64 static const WCHAR feature_unc_savedfilecheckW[] =
65 {'F','E','A','T','U','R','E','_','U','N','C','_','S','A','V','E','D','F','I','L','E','C','H','E','C','K',0};
66 static const WCHAR feature_get_url_dom_filepath_unencodedW[] =
67 {'F','E','A','T','U','R','E','_','G','E','T','_','U','R','L','_','D','O','M','_',
68 'F','I','L','E','P','A','T','H','_','U','N','E','N','C','O','D','E','D',0};
69 static const WCHAR feature_tabbed_browsingW[] =
70 {'F','E','A','T','U','R','E','_','T','A','B','B','E','D','_','B','R','O','W','S','I','N','G',0};
71 static const WCHAR feature_ssluxW[] =
72 {'F','E','A','T','U','R','E','_','S','S','L','U','X',0};
73 static const WCHAR feature_disable_navigation_soundsW[] =
74 {'F','E','A','T','U','R','E','_','D','I','S','A','B','L','E','_','N','A','V','I','G','A','T','I','O','N','_',
75 'S','O','U','N','D','S',0};
76 static const WCHAR feature_disable_legacy_compressionW[] =
77 {'F','E','A','T','U','R','E','_','D','I','S','A','B','L','E','_','L','E','G','A','C','Y','_',
78 'C','O','M','P','R','E','S','S','I','O','N',0};
79 static const WCHAR feature_force_addr_and_statusW[] =
80 {'F','E','A','T','U','R','E','_','F','O','R','C','E','_','A','D','D','R','_','A','N','D','_',
81 'S','T','A','T','U','S',0};
82 static const WCHAR feature_xmlhttpW[] =
83 {'F','E','A','T','U','R','E','_','X','M','L','H','T','T','P',0};
84 static const WCHAR feature_disable_telnet_protocolW[] =
85 {'F','E','A','T','U','R','E','_','D','I','S','A','B','L','E','_','T','E','L','N','E','T','_',
86 'P','R','O','T','O','C','O','L',0};
87 static const WCHAR feature_feedsW[] =
88 {'F','E','A','T','U','R','E','_','F','E','E','D','S',0};
89 static const WCHAR feature_block_input_promptsW[] =
90 {'F','E','A','T','U','R','E','_','B','L','O','C','K','_','I','N','P','U','T','_','P','R','O','M','P','T','S',0};
91
92 static CRITICAL_SECTION process_features_cs;
93 static CRITICAL_SECTION_DEBUG process_features_cs_dbg =
94 {
95 0, 0, &process_features_cs,
96 { &process_features_cs_dbg.ProcessLocksList, &process_features_cs_dbg.ProcessLocksList },
97 0, 0, { (DWORD_PTR)(__FILE__ ": process features") }
98 };
99 static CRITICAL_SECTION process_features_cs = { &process_features_cs_dbg, -1, 0, 0, 0, 0 };
100
101 typedef struct feature_control {
102 LPCWSTR feature_name;
103 BOOL enabled;
104 BOOL check_registry;
105 } feature_control;
106
107 /* IMPORTANT!!!
108 *
109 * This array is indexed using INTERNETFEATURELIST values, so everything must
110 * appear in the same order as it does in INTERNETFEATURELIST.
111 */
112 static feature_control process_feature_controls[FEATURE_ENTRY_COUNT] = {
113 {feature_object_cachingW, TRUE ,TRUE},
114 {feature_zone_elevationW, FALSE,TRUE},
115 {feature_mime_handlingW, FALSE,TRUE},
116 {feature_mime_sniffingW, FALSE,TRUE},
117 {feature_window_restrictionsW, FALSE,TRUE},
118 {feature_weboc_popupmanagementW, FALSE,TRUE},
119 {feature_behaviorsW, TRUE ,TRUE},
120 {feature_disable_mk_protocolW, TRUE ,TRUE},
121 {feature_localmachine_lockdownW, FALSE,TRUE},
122 {feature_securitybandW, FALSE,TRUE},
123 {feature_restrict_activexinstallW, FALSE,TRUE},
124 {feature_validate_navigate_urlW, FALSE,TRUE},
125 {feature_restrict_filedownloadW, FALSE,TRUE},
126 {feature_addon_managementW, FALSE,TRUE},
127 {feature_protocol_lockdownW, FALSE,TRUE},
128 {feature_http_username_password_disableW, FALSE,TRUE},
129 {feature_safe_bindtoobjectW, FALSE,TRUE},
130 {feature_unc_savedfilecheckW, FALSE,TRUE},
131 {feature_get_url_dom_filepath_unencodedW, TRUE ,TRUE},
132 {feature_tabbed_browsingW, FALSE,TRUE},
133 {feature_ssluxW, FALSE,TRUE},
134 {feature_disable_navigation_soundsW, FALSE,TRUE},
135 {feature_disable_legacy_compressionW, TRUE ,TRUE},
136 {feature_force_addr_and_statusW, FALSE,TRUE},
137 {feature_xmlhttpW, TRUE ,TRUE},
138 {feature_disable_telnet_protocolW, FALSE,TRUE},
139 {feature_feedsW, FALSE,TRUE},
140 {feature_block_input_promptsW, FALSE,TRUE}
141 };
142
143 static HRESULT parse_schema(LPCWSTR url, DWORD flags, LPWSTR result, DWORD size, DWORD *rsize)
144 {
145 WCHAR *ptr;
146 DWORD len = 0;
147
148 TRACE("(%s %08x %p %d %p)\n", debugstr_w(url), flags, result, size, rsize);
149
150 if(flags)
151 ERR("wrong flags\n");
152
153 ptr = strchrW(url, ':');
154 if(ptr)
155 len = ptr-url;
156
157 if(rsize)
158 *rsize = len;
159
160 if(len >= size)
161 return E_POINTER;
162
163 if(len)
164 memcpy(result, url, len*sizeof(WCHAR));
165 result[len] = 0;
166
167 return S_OK;
168 }
169
170 static HRESULT parse_canonicalize_url(LPCWSTR url, DWORD flags, LPWSTR result,
171 DWORD size, DWORD *rsize)
172 {
173 IInternetProtocolInfo *protocol_info;
174 DWORD prsize = size;
175 HRESULT hres;
176
177 TRACE("(%s %08x %p %d %p)\n", debugstr_w(url), flags, result, size, rsize);
178
179 protocol_info = get_protocol_info(url);
180
181 if(protocol_info) {
182 hres = IInternetProtocolInfo_ParseUrl(protocol_info, url, PARSE_CANONICALIZE,
183 flags, result, size, rsize, 0);
184 IInternetProtocolInfo_Release(protocol_info);
185 if(SUCCEEDED(hres))
186 return hres;
187 }
188
189 hres = UrlCanonicalizeW(url, result, &prsize, flags);
190
191 if(rsize)
192 *rsize = prsize;
193 return hres;
194 }
195
196 static HRESULT parse_security_url(LPCWSTR url, DWORD flags, LPWSTR result, DWORD size, DWORD *rsize)
197 {
198 IInternetProtocolInfo *protocol_info;
199 HRESULT hres;
200
201 TRACE("(%s %08x %p %d %p)\n", debugstr_w(url), flags, result, size, rsize);
202
203 protocol_info = get_protocol_info(url);
204
205 if(protocol_info) {
206 hres = IInternetProtocolInfo_ParseUrl(protocol_info, url, PARSE_SECURITY_URL,
207 flags, result, size, rsize, 0);
208 IInternetProtocolInfo_Release(protocol_info);
209 return hres;
210 }
211
212 return E_FAIL;
213 }
214
215 static HRESULT parse_encode(LPCWSTR url, DWORD flags, LPWSTR result, DWORD size, DWORD *rsize)
216 {
217 IInternetProtocolInfo *protocol_info;
218 DWORD prsize;
219 HRESULT hres;
220
221 TRACE("(%s %08x %p %d %p)\n", debugstr_w(url), flags, result, size, rsize);
222
223 protocol_info = get_protocol_info(url);
224
225 if(protocol_info) {
226 hres = IInternetProtocolInfo_ParseUrl(protocol_info, url, PARSE_ENCODE,
227 flags, result, size, rsize, 0);
228 IInternetProtocolInfo_Release(protocol_info);
229 if(SUCCEEDED(hres))
230 return hres;
231 }
232
233 prsize = size;
234 hres = UrlUnescapeW((LPWSTR)url, result, &prsize, flags);
235
236 if(rsize)
237 *rsize = prsize;
238
239 return hres;
240 }
241
242 static HRESULT parse_path_from_url(LPCWSTR url, DWORD flags, LPWSTR result, DWORD size, DWORD *rsize)
243 {
244 IInternetProtocolInfo *protocol_info;
245 DWORD prsize;
246 HRESULT hres;
247
248 TRACE("(%s %08x %p %d %p)\n", debugstr_w(url), flags, result, size, rsize);
249
250 protocol_info = get_protocol_info(url);
251
252 if(protocol_info) {
253 hres = IInternetProtocolInfo_ParseUrl(protocol_info, url, PARSE_PATH_FROM_URL,
254 flags, result, size, rsize, 0);
255 IInternetProtocolInfo_Release(protocol_info);
256 if(SUCCEEDED(hres))
257 return hres;
258 }
259
260 prsize = size;
261 hres = PathCreateFromUrlW(url, result, &prsize, 0);
262
263 if(rsize)
264 *rsize = prsize;
265 return hres;
266 }
267
268 static HRESULT parse_security_domain(LPCWSTR url, DWORD flags, LPWSTR result,
269 DWORD size, DWORD *rsize)
270 {
271 IInternetProtocolInfo *protocol_info;
272 HRESULT hres;
273
274 TRACE("(%s %08x %p %d %p)\n", debugstr_w(url), flags, result, size, rsize);
275
276 protocol_info = get_protocol_info(url);
277
278 if(protocol_info) {
279 hres = IInternetProtocolInfo_ParseUrl(protocol_info, url, PARSE_SECURITY_DOMAIN,
280 flags, result, size, rsize, 0);
281 IInternetProtocolInfo_Release(protocol_info);
282 if(SUCCEEDED(hres))
283 return hres;
284 }
285
286 return E_FAIL;
287 }
288
289 static HRESULT parse_domain(LPCWSTR url, DWORD flags, LPWSTR result,
290 DWORD size, DWORD *rsize)
291 {
292 IInternetProtocolInfo *protocol_info;
293 HRESULT hres;
294
295 TRACE("(%s %08x %p %d %p)\n", debugstr_w(url), flags, result, size, rsize);
296
297 protocol_info = get_protocol_info(url);
298
299 if(protocol_info) {
300 hres = IInternetProtocolInfo_ParseUrl(protocol_info, url, PARSE_DOMAIN,
301 flags, result, size, rsize, 0);
302 IInternetProtocolInfo_Release(protocol_info);
303 if(SUCCEEDED(hres))
304 return hres;
305 }
306
307 hres = UrlGetPartW(url, result, &size, URL_PART_HOSTNAME, flags);
308 if(rsize)
309 *rsize = size;
310
311 if(hres == E_POINTER)
312 return S_FALSE;
313
314 if(FAILED(hres))
315 return E_FAIL;
316 return S_OK;
317 }
318
319 static HRESULT parse_rootdocument(LPCWSTR url, DWORD flags, LPWSTR result,
320 DWORD size, DWORD *rsize)
321 {
322 IInternetProtocolInfo *protocol_info;
323 PARSEDURLW url_info;
324 HRESULT hres;
325
326 TRACE("(%s %08x %p %d %p)\n", debugstr_w(url), flags, result, size, rsize);
327
328 protocol_info = get_protocol_info(url);
329
330 if(protocol_info) {
331 hres = IInternetProtocolInfo_ParseUrl(protocol_info, url, PARSE_ROOTDOCUMENT,
332 flags, result, size, rsize, 0);
333 IInternetProtocolInfo_Release(protocol_info);
334 if(SUCCEEDED(hres))
335 return hres;
336 }
337
338 url_info.cbSize = sizeof(url_info);
339 if(FAILED(ParseURLW(url, &url_info)))
340 return E_FAIL;
341
342 switch(url_info.nScheme) {
343 case URL_SCHEME_FTP:
344 case URL_SCHEME_HTTP:
345 case URL_SCHEME_HTTPS:
346 if(url_info.cchSuffix<3 || *(url_info.pszSuffix)!='/'
347 || *(url_info.pszSuffix+1)!='/')
348 return E_FAIL;
349
350 if(size < url_info.cchProtocol+3) {
351 size = 0;
352 hres = UrlGetPartW(url, result, &size, URL_PART_HOSTNAME, flags);
353
354 if(rsize)
355 *rsize = size+url_info.cchProtocol+3;
356
357 if(hres == E_POINTER)
358 return S_FALSE;
359
360 return hres;
361 }
362
363 size -= url_info.cchProtocol+3;
364 hres = UrlGetPartW(url, result+url_info.cchProtocol+3,
365 &size, URL_PART_HOSTNAME, flags);
366
367 if(hres == E_POINTER)
368 return S_FALSE;
369
370 if(FAILED(hres))
371 return E_FAIL;
372
373 if(rsize)
374 *rsize = size+url_info.cchProtocol+3;
375
376 memcpy(result, url, (url_info.cchProtocol+3)*sizeof(WCHAR));
377 return hres;
378 default:
379 return E_FAIL;
380 }
381 }
382
383 /**************************************************************************
384 * CoInternetParseUrl (URLMON.@)
385 */
386 HRESULT WINAPI CoInternetParseUrl(LPCWSTR pwzUrl, PARSEACTION ParseAction, DWORD dwFlags,
387 LPWSTR pszResult, DWORD cchResult, DWORD *pcchResult, DWORD dwReserved)
388 {
389 if(dwReserved)
390 WARN("dwReserved = %d\n", dwReserved);
391
392 switch(ParseAction) {
393 case PARSE_CANONICALIZE:
394 return parse_canonicalize_url(pwzUrl, dwFlags, pszResult, cchResult, pcchResult);
395 case PARSE_SECURITY_URL:
396 return parse_security_url(pwzUrl, dwFlags, pszResult, cchResult, pcchResult);
397 case PARSE_ENCODE:
398 return parse_encode(pwzUrl, dwFlags, pszResult, cchResult, pcchResult);
399 case PARSE_PATH_FROM_URL:
400 return parse_path_from_url(pwzUrl, dwFlags, pszResult, cchResult, pcchResult);
401 case PARSE_SCHEMA:
402 return parse_schema(pwzUrl, dwFlags, pszResult, cchResult, pcchResult);
403 case PARSE_SECURITY_DOMAIN:
404 return parse_security_domain(pwzUrl, dwFlags, pszResult, cchResult, pcchResult);
405 case PARSE_DOMAIN:
406 return parse_domain(pwzUrl, dwFlags, pszResult, cchResult, pcchResult);
407 case PARSE_ROOTDOCUMENT:
408 return parse_rootdocument(pwzUrl, dwFlags, pszResult, cchResult, pcchResult);
409 default:
410 FIXME("not supported action %d\n", ParseAction);
411 }
412
413 return E_NOTIMPL;
414 }
415
416 /**************************************************************************
417 * CoInternetCombineUrl (URLMON.@)
418 */
419 HRESULT WINAPI CoInternetCombineUrl(LPCWSTR pwzBaseUrl, LPCWSTR pwzRelativeUrl,
420 DWORD dwCombineFlags, LPWSTR pwzResult, DWORD cchResult, DWORD *pcchResult,
421 DWORD dwReserved)
422 {
423 IInternetProtocolInfo *protocol_info;
424 DWORD size = cchResult;
425 HRESULT hres;
426
427 TRACE("(%s,%s,0x%08x,%p,%d,%p,%d)\n", debugstr_w(pwzBaseUrl),
428 debugstr_w(pwzRelativeUrl), dwCombineFlags, pwzResult, cchResult, pcchResult,
429 dwReserved);
430
431 protocol_info = get_protocol_info(pwzBaseUrl);
432
433 if(protocol_info) {
434 hres = IInternetProtocolInfo_CombineUrl(protocol_info, pwzBaseUrl, pwzRelativeUrl,
435 dwCombineFlags, pwzResult, cchResult, pcchResult, dwReserved);
436 IInternetProtocolInfo_Release(protocol_info);
437 if(SUCCEEDED(hres))
438 return hres;
439 }
440
441
442 hres = UrlCombineW(pwzBaseUrl, pwzRelativeUrl, pwzResult, &size, dwCombineFlags);
443
444 if(pcchResult)
445 *pcchResult = size;
446
447 return hres;
448 }
449
450 /**************************************************************************
451 * CoInternetCompareUrl (URLMON.@)
452 */
453 HRESULT WINAPI CoInternetCompareUrl(LPCWSTR pwzUrl1, LPCWSTR pwzUrl2, DWORD dwCompareFlags)
454 {
455 IInternetProtocolInfo *protocol_info;
456 HRESULT hres;
457
458 TRACE("(%s,%s,%08x)\n", debugstr_w(pwzUrl1), debugstr_w(pwzUrl2), dwCompareFlags);
459
460 protocol_info = get_protocol_info(pwzUrl1);
461
462 if(protocol_info) {
463 hres = IInternetProtocolInfo_CompareUrl(protocol_info, pwzUrl1, pwzUrl2, dwCompareFlags);
464 IInternetProtocolInfo_Release(protocol_info);
465 if(SUCCEEDED(hres))
466 return hres;
467 }
468
469 return UrlCompareW(pwzUrl1, pwzUrl2, dwCompareFlags) ? S_FALSE : S_OK;
470 }
471
472 /***********************************************************************
473 * CoInternetQueryInfo (URLMON.@)
474 *
475 * Retrieves information relevant to a specified URL
476 *
477 */
478 HRESULT WINAPI CoInternetQueryInfo(LPCWSTR pwzUrl, QUERYOPTION QueryOption,
479 DWORD dwQueryFlags, LPVOID pvBuffer, DWORD cbBuffer, DWORD *pcbBuffer,
480 DWORD dwReserved)
481 {
482 IInternetProtocolInfo *protocol_info;
483 HRESULT hres;
484
485 TRACE("(%s, %x, %x, %p, %x, %p, %x)\n", debugstr_w(pwzUrl),
486 QueryOption, dwQueryFlags, pvBuffer, cbBuffer, pcbBuffer, dwReserved);
487
488 protocol_info = get_protocol_info(pwzUrl);
489
490 if(protocol_info) {
491 hres = IInternetProtocolInfo_QueryInfo(protocol_info, pwzUrl, QueryOption, dwQueryFlags,
492 pvBuffer, cbBuffer, pcbBuffer, dwReserved);
493 IInternetProtocolInfo_Release(protocol_info);
494
495 return SUCCEEDED(hres) ? hres : E_FAIL;
496 }
497
498 switch(QueryOption) {
499 case QUERY_USES_NETWORK:
500 if(!pvBuffer || cbBuffer < sizeof(DWORD))
501 return E_FAIL;
502
503 *(DWORD*)pvBuffer = 0;
504 if(pcbBuffer)
505 *pcbBuffer = sizeof(DWORD);
506 break;
507
508 default:
509 FIXME("Not supported option %d\n", QueryOption);
510 return E_NOTIMPL;
511 }
512
513 return S_OK;
514 }
515
516 static void set_feature_on_process(INTERNETFEATURELIST feature, BOOL enable)
517 {
518 EnterCriticalSection(&process_features_cs);
519
520 process_feature_controls[feature].enabled = enable;
521 process_feature_controls[feature].check_registry = FALSE;
522
523 LeaveCriticalSection(&process_features_cs);
524 }
525
526 static HRESULT set_internet_feature(INTERNETFEATURELIST feature, DWORD flags, BOOL enable)
527 {
528 const DWORD supported_flags = SET_FEATURE_ON_PROCESS;
529
530 if(feature >= FEATURE_ENTRY_COUNT)
531 return E_FAIL;
532
533 if(flags & ~supported_flags)
534 FIXME("Unsupported flags: %08x\n", flags & ~supported_flags);
535
536 if(flags & SET_FEATURE_ON_PROCESS)
537 set_feature_on_process(feature, enable);
538
539 return S_OK;
540 }
541
542 static BOOL get_feature_from_reg(HKEY feature_control, LPCWSTR feature_name, LPCWSTR process_name, BOOL *enabled)
543 {
544 DWORD type, value, size;
545 HKEY feature;
546 DWORD res;
547
548 static const WCHAR wildcardW[] = {'*',0};
549
550 res = RegOpenKeyW(feature_control, feature_name, &feature);
551 if(res != ERROR_SUCCESS)
552 return FALSE;
553
554 size = sizeof(DWORD);
555 res = RegQueryValueExW(feature, process_name, NULL, &type, (BYTE*)&value, &size);
556 if(res != ERROR_SUCCESS || type != REG_DWORD) {
557 size = sizeof(DWORD);
558 res = RegQueryValueExW(feature, wildcardW, NULL, &type, (BYTE*)&value, &size);
559 }
560
561 RegCloseKey(feature);
562 if(res != ERROR_SUCCESS)
563 return FALSE;
564
565 if(type != REG_DWORD) {
566 WARN("Unexpected registry value type %d (expected REG_DWORD) for %s\n", type, debugstr_w(wildcardW));
567 return FALSE;
568 }
569
570 *enabled = value == 1;
571 return TRUE;
572 }
573
574 /* Assumes 'process_features_cs' is held. */
575 static HRESULT load_process_feature(INTERNETFEATURELIST feature)
576 {
577 DWORD res;
578 HKEY feature_control;
579 WCHAR module_name[MAX_PATH];
580 LPCWSTR process_name, feature_name;
581 HRESULT hres = S_FALSE;
582 BOOL check_hklm = FALSE;
583 BOOL enabled;
584
585 if (!GetModuleFileNameW(NULL, module_name, sizeof(module_name)/sizeof(WCHAR))) {
586 ERR("Failed to get module file name: %u\n", GetLastError());
587 return E_UNEXPECTED;
588 }
589
590 process_name = strrchrW(module_name, '\\');
591 if(!process_name) {
592 ERR("Invalid module file name: %s\n", debugstr_w(module_name));
593 return E_UNEXPECTED;
594 }
595
596 /* Skip past the '\\' in front of the filename. */
597 ++process_name;
598
599 feature_name = process_feature_controls[feature].feature_name;
600
601 res = RegOpenKeyW(HKEY_CURRENT_USER, feature_control_keyW, &feature_control);
602 if(res == ERROR_SUCCESS) {
603 if(get_feature_from_reg(feature_control, feature_name, process_name, &enabled)) {
604 hres = enabled ? S_OK : S_FALSE;
605 process_feature_controls[feature].enabled = enabled;
606 } else
607 /* We didn't find anything in HKCU, so check HKLM. */
608 check_hklm = TRUE;
609
610 RegCloseKey(feature_control);
611 }
612
613 if(check_hklm) {
614 res = RegOpenKeyW(HKEY_LOCAL_MACHINE, feature_control_keyW, &feature_control);
615 if(res == ERROR_SUCCESS) {
616 if(get_feature_from_reg(feature_control, feature_name, process_name, &enabled)) {
617 hres = enabled ? S_OK : S_FALSE;
618 process_feature_controls[feature].enabled = enabled;
619 }
620 RegCloseKey(feature_control);
621 }
622 }
623
624 /* Don't bother checking the registry again for this feature. */
625 process_feature_controls[feature].check_registry = FALSE;
626
627 return hres;
628 }
629
630 static HRESULT get_feature_from_process(INTERNETFEATURELIST feature)
631 {
632 HRESULT hres = S_OK;
633
634 EnterCriticalSection(&process_features_cs);
635
636 /* Try loading the feature from the registry, if it hasn't already
637 * been done.
638 */
639 if(process_feature_controls[feature].check_registry)
640 hres = load_process_feature(feature);
641 if(SUCCEEDED(hres))
642 hres = process_feature_controls[feature].enabled ? S_OK : S_FALSE;
643
644 LeaveCriticalSection(&process_features_cs);
645
646 return hres;
647 }
648
649 static HRESULT get_internet_feature(INTERNETFEATURELIST feature, DWORD flags)
650 {
651 HRESULT hres;
652
653 if(feature >= FEATURE_ENTRY_COUNT)
654 return E_FAIL;
655
656 if(flags == GET_FEATURE_FROM_PROCESS)
657 hres = get_feature_from_process(feature);
658 else {
659 FIXME("Unsupported flags: %08x\n", flags);
660 hres = E_NOTIMPL;
661 }
662
663 return hres;
664 }
665
666 /***********************************************************************
667 * CoInternetSetFeatureEnabled (URLMON.@)
668 */
669 HRESULT WINAPI CoInternetSetFeatureEnabled(INTERNETFEATURELIST FeatureEntry, DWORD dwFlags, BOOL fEnable)
670 {
671 TRACE("(%d, %08x, %x)\n", FeatureEntry, dwFlags, fEnable);
672 return set_internet_feature(FeatureEntry, dwFlags, fEnable);
673 }
674
675 /***********************************************************************
676 * CoInternetIsFeatureEnabled (URLMON.@)
677 */
678 HRESULT WINAPI CoInternetIsFeatureEnabled(INTERNETFEATURELIST FeatureEntry, DWORD dwFlags)
679 {
680 TRACE("(%d, %08x)\n", FeatureEntry, dwFlags);
681 return get_internet_feature(FeatureEntry, dwFlags);
682 }
683
684 /***********************************************************************
685 * CoInternetIsFeatureEnabledForUrl (URLMON.@)
686 */
687 HRESULT WINAPI CoInternetIsFeatureEnabledForUrl(INTERNETFEATURELIST FeatureEntry, DWORD dwFlags, LPCWSTR szURL,
688 IInternetSecurityManager *pSecMgr)
689 {
690 DWORD urlaction = 0;
691 HRESULT hres;
692
693 TRACE("(%d %08x %s %p)\n", FeatureEntry, dwFlags, debugstr_w(szURL), pSecMgr);
694
695 if(FeatureEntry == FEATURE_MIME_SNIFFING)
696 urlaction = URLACTION_FEATURE_MIME_SNIFFING;
697 else if(FeatureEntry == FEATURE_WINDOW_RESTRICTIONS)
698 urlaction = URLACTION_FEATURE_WINDOW_RESTRICTIONS;
699 else if(FeatureEntry == FEATURE_ZONE_ELEVATION)
700 urlaction = URLACTION_FEATURE_ZONE_ELEVATION;
701
702 if(!szURL || !urlaction || !pSecMgr)
703 return CoInternetIsFeatureEnabled(FeatureEntry, dwFlags);
704
705 switch(dwFlags) {
706 case GET_FEATURE_FROM_THREAD:
707 case GET_FEATURE_FROM_THREAD_LOCALMACHINE:
708 case GET_FEATURE_FROM_THREAD_INTRANET:
709 case GET_FEATURE_FROM_THREAD_TRUSTED:
710 case GET_FEATURE_FROM_THREAD_INTERNET:
711 case GET_FEATURE_FROM_THREAD_RESTRICTED:
712 FIXME("unsupported flags %x\n", dwFlags);
713 return E_NOTIMPL;
714
715 case GET_FEATURE_FROM_PROCESS:
716 hres = CoInternetIsFeatureEnabled(FeatureEntry, dwFlags);
717 if(hres != S_OK)
718 return hres;
719 /* fall through */
720
721 default: {
722 DWORD policy = URLPOLICY_DISALLOW;
723
724 hres = IInternetSecurityManager_ProcessUrlAction(pSecMgr, szURL, urlaction,
725 (BYTE*)&policy, sizeof(DWORD), NULL, 0, PUAF_NOUI, 0);
726 if(hres!=S_OK || policy!=URLPOLICY_ALLOW)
727 return S_OK;
728 return S_FALSE;
729 }
730 }
731 }
732
733 /***********************************************************************
734 * CoInternetIsFeatureZoneElevationEnabled (URLMON.@)
735 */
736 HRESULT WINAPI CoInternetIsFeatureZoneElevationEnabled(LPCWSTR szFromURL, LPCWSTR szToURL,
737 IInternetSecurityManager *pSecMgr, DWORD dwFlags)
738 {
739 HRESULT hres;
740
741 TRACE("(%s %s %p %x)\n", debugstr_w(szFromURL), debugstr_w(szToURL), pSecMgr, dwFlags);
742
743 if(!pSecMgr || !szToURL)
744 return CoInternetIsFeatureEnabled(FEATURE_ZONE_ELEVATION, dwFlags);
745
746 switch(dwFlags) {
747 case GET_FEATURE_FROM_THREAD:
748 case GET_FEATURE_FROM_THREAD_LOCALMACHINE:
749 case GET_FEATURE_FROM_THREAD_INTRANET:
750 case GET_FEATURE_FROM_THREAD_TRUSTED:
751 case GET_FEATURE_FROM_THREAD_INTERNET:
752 case GET_FEATURE_FROM_THREAD_RESTRICTED:
753 FIXME("unsupported flags %x\n", dwFlags);
754 return E_NOTIMPL;
755
756 case GET_FEATURE_FROM_PROCESS:
757 hres = CoInternetIsFeatureEnabled(FEATURE_ZONE_ELEVATION, dwFlags);
758 if(hres != S_OK)
759 return hres;
760 /* fall through */
761
762 default: {
763 DWORD policy = URLPOLICY_DISALLOW;
764
765 hres = IInternetSecurityManager_ProcessUrlAction(pSecMgr, szToURL,
766 URLACTION_FEATURE_ZONE_ELEVATION, (BYTE*)&policy, sizeof(DWORD),
767 NULL, 0, PUAF_NOUI, 0);
768 if(FAILED(hres))
769 return S_OK;
770
771 switch(policy) {
772 case URLPOLICY_ALLOW:
773 return S_FALSE;
774 case URLPOLICY_QUERY:
775 FIXME("Ask user dialog not implemented\n");
776 default:
777 return S_OK;
778 }
779 }
780 }
781 }