Sync with trunk r63174.
[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): stub\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 return E_NOTIMPL;
536 }
537
538 if(flags & SET_FEATURE_ON_PROCESS)
539 set_feature_on_process(feature, enable);
540
541 return S_OK;
542 }
543
544 static BOOL get_feature_from_reg(HKEY feature_control, LPCWSTR feature_name, LPCWSTR process_name, BOOL *enabled)
545 {
546 DWORD type, value, size;
547 HKEY feature;
548 DWORD res;
549
550 static const WCHAR wildcardW[] = {'*',0};
551
552 res = RegOpenKeyW(feature_control, feature_name, &feature);
553 if(res != ERROR_SUCCESS)
554 return FALSE;
555
556 size = sizeof(DWORD);
557 res = RegQueryValueExW(feature, process_name, NULL, &type, (BYTE*)&value, &size);
558 if(res != ERROR_SUCCESS || type != REG_DWORD) {
559 size = sizeof(DWORD);
560 res = RegQueryValueExW(feature, wildcardW, NULL, &type, (BYTE*)&value, &size);
561 }
562
563 RegCloseKey(feature);
564 if(res != ERROR_SUCCESS)
565 return FALSE;
566
567 if(type != REG_DWORD) {
568 WARN("Unexpected registry value type %d (expected REG_DWORD) for %s\n", type, debugstr_w(wildcardW));
569 return FALSE;
570 }
571
572 *enabled = value == 1;
573 return TRUE;
574 }
575
576 /* Assumes 'process_features_cs' is held. */
577 static HRESULT load_process_feature(INTERNETFEATURELIST feature)
578 {
579 DWORD res;
580 HKEY feature_control;
581 WCHAR module_name[MAX_PATH];
582 LPCWSTR process_name, feature_name;
583 HRESULT hres = S_FALSE;
584 BOOL check_hklm = FALSE;
585 BOOL enabled;
586
587 if (!GetModuleFileNameW(NULL, module_name, sizeof(module_name)/sizeof(WCHAR))) {
588 ERR("Failed to get module file name: %u\n", GetLastError());
589 return E_UNEXPECTED;
590 }
591
592 process_name = strrchrW(module_name, '\\');
593 if(!process_name) {
594 ERR("Invalid module file name: %s\n", debugstr_w(module_name));
595 return E_UNEXPECTED;
596 }
597
598 /* Skip past the '\\' in front of the filename. */
599 ++process_name;
600
601 feature_name = process_feature_controls[feature].feature_name;
602
603 res = RegOpenKeyW(HKEY_CURRENT_USER, feature_control_keyW, &feature_control);
604 if(res == ERROR_SUCCESS) {
605 if(get_feature_from_reg(feature_control, feature_name, process_name, &enabled)) {
606 hres = enabled ? S_OK : S_FALSE;
607 process_feature_controls[feature].enabled = enabled;
608 } else
609 /* We didn't find anything in HKCU, so check HKLM. */
610 check_hklm = TRUE;
611
612 RegCloseKey(feature_control);
613 }
614
615 if(check_hklm) {
616 res = RegOpenKeyW(HKEY_LOCAL_MACHINE, feature_control_keyW, &feature_control);
617 if(res == ERROR_SUCCESS) {
618 if(get_feature_from_reg(feature_control, feature_name, process_name, &enabled)) {
619 hres = enabled ? S_OK : S_FALSE;
620 process_feature_controls[feature].enabled = enabled;
621 }
622 RegCloseKey(feature_control);
623 }
624 }
625
626 /* Don't bother checking the registry again for this feature. */
627 process_feature_controls[feature].check_registry = FALSE;
628
629 return hres;
630 }
631
632 static HRESULT get_feature_from_process(INTERNETFEATURELIST feature)
633 {
634 HRESULT hres = S_OK;
635
636 EnterCriticalSection(&process_features_cs);
637
638 /* Try loading the feature from the registry, if it hasn't already
639 * been done.
640 */
641 if(process_feature_controls[feature].check_registry)
642 hres = load_process_feature(feature);
643 if(SUCCEEDED(hres))
644 hres = process_feature_controls[feature].enabled ? S_OK : S_FALSE;
645
646 LeaveCriticalSection(&process_features_cs);
647
648 return hres;
649 }
650
651 static HRESULT get_internet_feature(INTERNETFEATURELIST feature, DWORD flags)
652 {
653 HRESULT hres;
654
655 if(feature >= FEATURE_ENTRY_COUNT)
656 return E_FAIL;
657
658 if(flags == GET_FEATURE_FROM_PROCESS)
659 hres = get_feature_from_process(feature);
660 else {
661 FIXME("Unsupported flags: %08x\n", flags);
662 hres = E_NOTIMPL;
663 }
664
665 return hres;
666 }
667
668 /***********************************************************************
669 * CoInternetSetFeatureEnabled (URLMON.@)
670 */
671 HRESULT WINAPI CoInternetSetFeatureEnabled(INTERNETFEATURELIST FeatureEntry, DWORD dwFlags, BOOL fEnable)
672 {
673 TRACE("(%d, %08x, %x)\n", FeatureEntry, dwFlags, fEnable);
674 return set_internet_feature(FeatureEntry, dwFlags, fEnable);
675 }
676
677 /***********************************************************************
678 * CoInternetIsFeatureEnabled (URLMON.@)
679 */
680 HRESULT WINAPI CoInternetIsFeatureEnabled(INTERNETFEATURELIST FeatureEntry, DWORD dwFlags)
681 {
682 TRACE("(%d, %08x)\n", FeatureEntry, dwFlags);
683 return get_internet_feature(FeatureEntry, dwFlags);
684 }
685
686 /***********************************************************************
687 * CoInternetIsFeatureEnabledForUrl (URLMON.@)
688 */
689 HRESULT WINAPI CoInternetIsFeatureEnabledForUrl(INTERNETFEATURELIST FeatureEntry, DWORD dwFlags, LPCWSTR szURL,
690 IInternetSecurityManager *pSecMgr)
691 {
692 DWORD urlaction = 0;
693 HRESULT hres;
694
695 TRACE("(%d %08x %s %p)\n", FeatureEntry, dwFlags, debugstr_w(szURL), pSecMgr);
696
697 if(FeatureEntry == FEATURE_MIME_SNIFFING)
698 urlaction = URLACTION_FEATURE_MIME_SNIFFING;
699 else if(FeatureEntry == FEATURE_WINDOW_RESTRICTIONS)
700 urlaction = URLACTION_FEATURE_WINDOW_RESTRICTIONS;
701 else if(FeatureEntry == FEATURE_ZONE_ELEVATION)
702 urlaction = URLACTION_FEATURE_ZONE_ELEVATION;
703
704 if(!szURL || !urlaction || !pSecMgr)
705 return CoInternetIsFeatureEnabled(FeatureEntry, dwFlags);
706
707 switch(dwFlags) {
708 case GET_FEATURE_FROM_THREAD:
709 case GET_FEATURE_FROM_THREAD_LOCALMACHINE:
710 case GET_FEATURE_FROM_THREAD_INTRANET:
711 case GET_FEATURE_FROM_THREAD_TRUSTED:
712 case GET_FEATURE_FROM_THREAD_INTERNET:
713 case GET_FEATURE_FROM_THREAD_RESTRICTED:
714 FIXME("unsupported flags %x\n", dwFlags);
715 return E_NOTIMPL;
716
717 case GET_FEATURE_FROM_PROCESS:
718 hres = CoInternetIsFeatureEnabled(FeatureEntry, dwFlags);
719 if(hres != S_OK)
720 return hres;
721 /* fall through */
722
723 default: {
724 DWORD policy = URLPOLICY_DISALLOW;
725
726 hres = IInternetSecurityManager_ProcessUrlAction(pSecMgr, szURL, urlaction,
727 (BYTE*)&policy, sizeof(DWORD), NULL, 0, PUAF_NOUI, 0);
728 if(hres!=S_OK || policy!=URLPOLICY_ALLOW)
729 return S_OK;
730 return S_FALSE;
731 }
732 }
733 }
734
735 /***********************************************************************
736 * CoInternetIsFeatureZoneElevationEnabled (URLMON.@)
737 */
738 HRESULT WINAPI CoInternetIsFeatureZoneElevationEnabled(LPCWSTR szFromURL, LPCWSTR szToURL,
739 IInternetSecurityManager *pSecMgr, DWORD dwFlags)
740 {
741 HRESULT hres;
742
743 TRACE("(%s %s %p %x)\n", debugstr_w(szFromURL), debugstr_w(szToURL), pSecMgr, dwFlags);
744
745 if(!pSecMgr || !szToURL)
746 return CoInternetIsFeatureEnabled(FEATURE_ZONE_ELEVATION, dwFlags);
747
748 switch(dwFlags) {
749 case GET_FEATURE_FROM_THREAD:
750 case GET_FEATURE_FROM_THREAD_LOCALMACHINE:
751 case GET_FEATURE_FROM_THREAD_INTRANET:
752 case GET_FEATURE_FROM_THREAD_TRUSTED:
753 case GET_FEATURE_FROM_THREAD_INTERNET:
754 case GET_FEATURE_FROM_THREAD_RESTRICTED:
755 FIXME("unsupported flags %x\n", dwFlags);
756 return E_NOTIMPL;
757
758 case GET_FEATURE_FROM_PROCESS:
759 hres = CoInternetIsFeatureEnabled(FEATURE_ZONE_ELEVATION, dwFlags);
760 if(hres != S_OK)
761 return hres;
762 /* fall through */
763
764 default: {
765 DWORD policy = URLPOLICY_DISALLOW;
766
767 hres = IInternetSecurityManager_ProcessUrlAction(pSecMgr, szToURL,
768 URLACTION_FEATURE_ZONE_ELEVATION, (BYTE*)&policy, sizeof(DWORD),
769 NULL, 0, PUAF_NOUI, 0);
770 if(FAILED(hres))
771 return S_OK;
772
773 switch(policy) {
774 case URLPOLICY_ALLOW:
775 return S_FALSE;
776 case URLPOLICY_QUERY:
777 FIXME("Ask user dialog not implemented\n");
778 default:
779 return S_OK;
780 }
781 }
782 }
783 }