ntdll: Prefer loading native manifests over Wine ones.
[wine] / dlls / urlmon / sec_mgr.c
1 /*
2  * Internet Security and Zone Manager
3  *
4  * Copyright (c) 2004 Huw D M Davies
5  * Copyright 2004 Jacek Caban
6  * Copyright 2009 Detlef Riekenberg
7  * Copyright 2011 Thomas Mullaly for CodeWeavers
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23
24 #include <stdio.h>
25
26 #include "urlmon_main.h"
27 #include "winreg.h"
28 #include "wininet.h"
29
30 #define NO_SHLWAPI_REG
31 #include "shlwapi.h"
32
33 #include "wine/debug.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
36
37 static const WCHAR currentlevelW[] = {'C','u','r','r','e','n','t','L','e','v','e','l',0};
38 static const WCHAR descriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
39 static const WCHAR displaynameW[] = {'D','i','s','p','l','a','y','N','a','m','e',0};
40 static const WCHAR fileW[] = {'f','i','l','e',0};
41 static const WCHAR flagsW[] = {'F','l','a','g','s',0};
42 static const WCHAR iconW[] = {'I','c','o','n',0};
43 static const WCHAR minlevelW[] = {'M','i','n','L','e','v','e','l',0};
44 static const WCHAR recommendedlevelW[] = {'R','e','c','o','m','m','e','n','d','e','d',
45                                           'L','e','v','e','l',0};
46 static const WCHAR wszZonesKey[] = {'S','o','f','t','w','a','r','e','\\',
47                                     'M','i','c','r','o','s','o','f','t','\\',
48                                     'W','i','n','d','o','w','s','\\',
49                                     'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
50                                     'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s','\\',
51                                     'Z','o','n','e','s','\\',0};
52 static const WCHAR wszZoneMapDomainsKey[] = {'S','o','f','t','w','a','r','e','\\',
53                                              'M','i','c','r','o','s','o','f','t','\\',
54                                              'W','i','n','d','o','w','s','\\',
55                                              'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
56                                              'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s','\\',
57                                              'Z','o','n','e','M','a','p','\\',
58                                              'D','o','m','a','i','n','s',0};
59
60 /********************************************************************
61  * get_string_from_reg [internal]
62  *
63  * helper to get a string from the reg.
64  *
65  */
66 static void get_string_from_reg(HKEY hcu, HKEY hklm, LPCWSTR name, LPWSTR out, DWORD maxlen)
67 {
68     DWORD type = REG_SZ;
69     DWORD len = maxlen * sizeof(WCHAR);
70     DWORD res;
71
72     res = RegQueryValueExW(hcu, name, NULL, &type, (LPBYTE) out, &len);
73
74     if (res && hklm) {
75         len = maxlen * sizeof(WCHAR);
76         type = REG_SZ;
77         res = RegQueryValueExW(hklm, name, NULL, &type, (LPBYTE) out, &len);
78     }
79
80     if (res) {
81         TRACE("%s failed: %d\n", debugstr_w(name), res);
82         *out = '\0';
83     }
84 }
85
86 /********************************************************************
87  * get_dword_from_reg [internal]
88  *
89  * helper to get a dword from the reg.
90  *
91  */
92 static void get_dword_from_reg(HKEY hcu, HKEY hklm, LPCWSTR name, LPDWORD out)
93 {
94     DWORD type = REG_DWORD;
95     DWORD len = sizeof(DWORD);
96     DWORD res;
97
98     res = RegQueryValueExW(hcu, name, NULL, &type, (LPBYTE) out, &len);
99
100     if (res && hklm) {
101         len = sizeof(DWORD);
102         type = REG_DWORD;
103         res = RegQueryValueExW(hklm, name, NULL, &type, (LPBYTE) out, &len);
104     }
105
106     if (res) {
107         TRACE("%s failed: %d\n", debugstr_w(name), res);
108         *out = 0;
109     }
110 }
111
112 static HRESULT get_zone_from_reg(LPCWSTR schema, DWORD *zone)
113 {
114     DWORD res, size;
115     HKEY hkey;
116
117     static const WCHAR wszZoneMapProtocolKey[] =
118         {'S','o','f','t','w','a','r','e','\\',
119          'M','i','c','r','o','s','o','f','t','\\',
120          'W','i','n','d','o','w','s','\\',
121          'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
122          'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s','\\',
123          'Z','o','n','e','M','a','p','\\',
124          'P','r','o','t','o','c','o','l','D','e','f','a','u','l','t','s',0};
125
126     res = RegOpenKeyW(HKEY_CURRENT_USER, wszZoneMapProtocolKey, &hkey);
127     if(res != ERROR_SUCCESS) {
128         ERR("Could not open key %s\n", debugstr_w(wszZoneMapProtocolKey));
129         return E_UNEXPECTED;
130     }
131
132     size = sizeof(DWORD);
133     res = RegQueryValueExW(hkey, schema, NULL, NULL, (PBYTE)zone, &size);
134     RegCloseKey(hkey);
135     if(res == ERROR_SUCCESS)
136         return S_OK;
137
138     res = RegOpenKeyW(HKEY_LOCAL_MACHINE, wszZoneMapProtocolKey, &hkey);
139     if(res != ERROR_SUCCESS) {
140         ERR("Could not open key %s\n", debugstr_w(wszZoneMapProtocolKey));
141         return E_UNEXPECTED;
142     }
143
144     size = sizeof(DWORD);
145     res = RegQueryValueExW(hkey, schema, NULL, NULL, (PBYTE)zone, &size);
146     RegCloseKey(hkey);
147     if(res == ERROR_SUCCESS)
148         return S_OK;
149
150     *zone = 3;
151     return S_OK;
152 }
153
154 /********************************************************************
155  * matches_domain_pattern [internal]
156  *
157  * Checks if the given string matches the specified domain pattern.
158  *
159  * This function looks for explicit wildcard domain components iff
160  * they appear at the very beginning of the 'pattern' string
161  *
162  *  pattern = "*.google.com"
163  */
164 static BOOL matches_domain_pattern(LPCWSTR pattern, LPCWSTR str, BOOL implicit_wildcard, LPCWSTR *matched)
165 {
166     BOOL matches = FALSE;
167     DWORD pattern_len = strlenW(pattern);
168     DWORD str_len = strlenW(str);
169
170     TRACE("(%d) Checking if %s matches %s\n", implicit_wildcard, debugstr_w(str), debugstr_w(pattern));
171
172     *matched = NULL;
173     if(str_len >= pattern_len) {
174         /* Check if there's an explicit wildcard in the pattern. */
175         if(pattern[0] == '*' && pattern[1] == '.') {
176             /* Make sure that 'str' matches the wildcard pattern.
177              *
178              * Example:
179              *  pattern = "*.google.com"
180              *
181              * So in this case 'str' would have to end with ".google.com" in order
182              * to map to this pattern.
183              */
184             if(str_len >= pattern_len+1 && !strcmpiW(str+(str_len-pattern_len+1), pattern+1)) {
185                 /* Check if there's another '.' inside of the "unmatched" portion
186                  * of 'str'.
187                  *
188                  * Example:
189                  *  pattern = "*.google.com"
190                  *  str     = "test.testing.google.com"
191                  *
192                  * The currently matched portion is ".google.com" in 'str', we need
193                  * see if there's a '.' inside of the unmatched portion ("test.testing"), because
194                  * if there is and 'implicit_wildcard' isn't set, then this isn't
195                  * a match.
196                  */
197                 const WCHAR *ptr;
198                 if(str_len > pattern_len+1 && (ptr = memrchrW(str, '.', str_len-pattern_len-2))) {
199                     if(implicit_wildcard) {
200                         matches = TRUE;
201                         *matched = ptr+1;
202                     }
203                 } else {
204                     matches = TRUE;
205                     *matched = str;
206                 }
207             }
208         } else if(implicit_wildcard && str_len > pattern_len) {
209             /* When the pattern has an implicit wildcard component, it means
210              * that anything goes in 'str' as long as it ends with the pattern
211              * and that the beginning of the match has a '.' before it.
212              *
213              * Example:
214              *  pattern = "google.com"
215              *  str     = "www.google.com"
216              *
217              * Implicitly matches the pattern, where as:
218              *
219              *  pattern = "google.com"
220              *  str     = "wwwgoogle.com"
221              *
222              * Doesn't match the pattern.
223              */
224             if(str_len > pattern_len) {
225                 if(str[str_len-pattern_len-1] == '.' && !strcmpiW(str+(str_len-pattern_len), pattern)) {
226                     matches = TRUE;
227                     *matched = str+(str_len-pattern_len);
228                 }
229             }
230         } else {
231             /* The pattern doesn't have an implicit wildcard, or an explicit wildcard,
232              * so 'str' has to be an exact match to the 'pattern'.
233              */
234             if(!strcmpiW(str, pattern)) {
235                 matches = TRUE;
236                 *matched = str;
237             }
238         }
239     }
240
241     if(matches)
242         TRACE("Found a match: matched=%s\n", debugstr_w(*matched));
243     else
244         TRACE("No match found\n");
245
246     return matches;
247 }
248
249 static BOOL get_zone_for_scheme(HKEY key, LPCWSTR schema, DWORD *zone)
250 {
251     static const WCHAR wildcardW[] = {'*',0};
252
253     DWORD res;
254     DWORD size = sizeof(DWORD);
255     DWORD type;
256
257     /* See if the key contains a value for the scheme first. */
258     res = RegQueryValueExW(key, schema, NULL, &type, (BYTE*)zone, &size);
259     if(res == ERROR_SUCCESS) {
260         if(type == REG_DWORD)
261             return TRUE;
262         WARN("Unexpected value type %d for value %s, expected REG_DWORD\n", type, debugstr_w(schema));
263     }
264
265     /* Try to get the zone for the wildcard scheme. */
266     size = sizeof(DWORD);
267     res = RegQueryValueExW(key, wildcardW, NULL, &type, (BYTE*)zone, &size);
268     if(res != ERROR_SUCCESS)
269         return FALSE;
270
271     if(type != REG_DWORD) {
272         WARN("Unexpected value type %d for value %s, expected REG_DWORD\n", type, debugstr_w(wildcardW));
273         return FALSE;
274     }
275
276     return TRUE;
277 }
278
279 /********************************************************************
280  * search_domain_for_zone [internal]
281  *
282  * Searches the specified 'domain' registry key to see if 'host' maps into it, or any
283  * of it's subdomain registry keys.
284  *
285  * Returns S_OK if a match is found, S_FALSE if no matches were found, or an error code.
286  */
287 static HRESULT search_domain_for_zone(HKEY domains, LPCWSTR domain, DWORD domain_len, LPCWSTR schema,
288                                       LPCWSTR host, DWORD host_len, DWORD *zone)
289 {
290     BOOL found = FALSE;
291     HKEY domain_key;
292     DWORD res;
293     LPCWSTR matched;
294
295     if(host_len >= domain_len && matches_domain_pattern(domain, host, TRUE, &matched)) {
296         res = RegOpenKeyW(domains, domain, &domain_key);
297         if(res != ERROR_SUCCESS) {
298             ERR("Failed to open domain key %s: %d\n", debugstr_w(domain), res);
299             return E_UNEXPECTED;
300         }
301
302         if(matched == host)
303             found = get_zone_for_scheme(domain_key, schema, zone);
304         else {
305             INT domain_offset;
306             DWORD subdomain_count, subdomain_len;
307             BOOL check_domain = TRUE;
308
309             find_domain_name(domain, domain_len, &domain_offset);
310
311             res = RegQueryInfoKeyW(domain_key, NULL, NULL, NULL, &subdomain_count, &subdomain_len,
312                                    NULL, NULL, NULL, NULL, NULL, NULL);
313             if(res != ERROR_SUCCESS) {
314                 ERR("Unable to query info for key %s: %d\n", debugstr_w(domain), res);
315                 RegCloseKey(domain_key);
316                 return E_UNEXPECTED;
317             }
318
319             if(subdomain_count) {
320                 WCHAR *subdomain;
321                 WCHAR *component;
322                 DWORD i;
323
324                 subdomain = heap_alloc((subdomain_len+1)*sizeof(WCHAR));
325                 if(!subdomain) {
326                     RegCloseKey(domain_key);
327                     return E_OUTOFMEMORY;
328                 }
329
330                 component = heap_strndupW(host, matched-host-1);
331                 if(!component) {
332                     heap_free(subdomain);
333                     RegCloseKey(domain_key);
334                     return E_OUTOFMEMORY;
335                 }
336
337                 for(i = 0; i < subdomain_count; ++i) {
338                     DWORD len = subdomain_len+1;
339                     const WCHAR *sub_matched;
340
341                     res = RegEnumKeyExW(domain_key, i, subdomain, &len, NULL, NULL, NULL, NULL);
342                     if(res != ERROR_SUCCESS) {
343                         heap_free(component);
344                         heap_free(subdomain);
345                         RegCloseKey(domain_key);
346                         return E_UNEXPECTED;
347                     }
348
349                     if(matches_domain_pattern(subdomain, component, FALSE, &sub_matched)) {
350                         HKEY subdomain_key;
351
352                         res = RegOpenKeyW(domain_key, subdomain, &subdomain_key);
353                         if(res != ERROR_SUCCESS) {
354                             ERR("Unable to open subdomain key %s of %s: %d\n", debugstr_w(subdomain),
355                                 debugstr_w(domain), res);
356                             heap_free(component);
357                             heap_free(subdomain);
358                             RegCloseKey(domain_key);
359                             return E_UNEXPECTED;
360                         }
361
362                         found = get_zone_for_scheme(subdomain_key, schema, zone);
363                         check_domain = FALSE;
364                         RegCloseKey(subdomain_key);
365                         break;
366                     }
367                 }
368                 heap_free(subdomain);
369                 heap_free(component);
370             }
371
372             /* There's a chance that 'host' implicitly mapped into 'domain', in
373              * which case we check to see if 'domain' contains zone information.
374              *
375              * This can only happen if 'domain' is it's own domain name.
376              *  Example:
377              *      "google.com" (domain name = "google.com")
378              *
379              *  So if:
380              *      host = "www.google.com"
381              *
382              *  Then host would map directly into the "google.com" domain key.
383              *
384              * If 'domain' has more than just it's domain name, or it does not
385              * have a domain name, then we don't perform the check. The reason
386              * for this is that these domains don't allow implicit mappings.
387              *  Example:
388              *      domain = "org" (has no domain name)
389              *      host   = "www.org"
390              *
391              *  The mapping would only happen if the "org" key had an explicit subkey
392              *  called "www".
393              */
394             if(check_domain && !domain_offset && !strchrW(host, matched-host-1))
395                 found = get_zone_for_scheme(domain_key, schema, zone);
396         }
397         RegCloseKey(domain_key);
398     }
399
400     return found ? S_OK : S_FALSE;
401 }
402
403 static HRESULT search_for_domain_mapping(HKEY domains, LPCWSTR schema, LPCWSTR host, DWORD host_len, DWORD *zone)
404 {
405     WCHAR *domain;
406     DWORD domain_count, domain_len, i;
407     DWORD res;
408     HRESULT hres = S_FALSE;
409
410     res = RegQueryInfoKeyW(domains, NULL, NULL, NULL, &domain_count, &domain_len,
411                            NULL, NULL, NULL, NULL, NULL, NULL);
412     if(res != ERROR_SUCCESS) {
413         WARN("Failed to retrieve information about key\n");
414         return E_UNEXPECTED;
415     }
416
417     if(!domain_count)
418         return S_FALSE;
419
420     domain = heap_alloc((domain_len+1)*sizeof(WCHAR));
421     if(!domain)
422         return E_OUTOFMEMORY;
423
424     for(i = 0; i < domain_count; ++i) {
425         DWORD len = domain_len+1;
426
427         res = RegEnumKeyExW(domains, i, domain, &len, NULL, NULL, NULL, NULL);
428         if(res != ERROR_SUCCESS) {
429             heap_free(domain);
430             return E_UNEXPECTED;
431         }
432
433         hres = search_domain_for_zone(domains, domain, len, schema, host, host_len, zone);
434         if(FAILED(hres) || hres == S_OK)
435             break;
436     }
437
438     heap_free(domain);
439     return hres;
440 }
441
442 static HRESULT get_zone_from_domains(LPCWSTR url, LPCWSTR schema, DWORD *zone)
443 {
444     HRESULT hres;
445     WCHAR *host_name;
446     DWORD host_len = lstrlenW(url)+1;
447     DWORD res;
448     HKEY domains;
449
450     host_name = heap_alloc(host_len*sizeof(WCHAR));
451     if(!host_name)
452         return E_OUTOFMEMORY;
453
454     hres = CoInternetParseUrl(url, PARSE_DOMAIN, 0, host_name, host_len, &host_len, 0);
455     if(hres == S_FALSE) {
456         WCHAR *tmp = heap_realloc(host_name, (host_len+1)*sizeof(WCHAR));
457         if(!tmp) {
458             heap_free(host_name);
459             return E_OUTOFMEMORY;
460         }
461
462         host_name = tmp;
463         hres = CoInternetParseUrl(url, PARSE_DOMAIN, 0, host_name, host_len+1, &host_len, 0);
464     }
465
466     /* Windows doesn't play nice with unknown scheme types when it tries
467      * to check if a host name maps into any domains.
468      *
469      * The reason is with how CoInternetParseUrl handles unknown scheme types
470      * when it's parsing the domain of a URL (IE it always returns E_FAIL).
471      *
472      * Windows doesn't compensate for this and simply doesn't check if
473      * the URL maps into any domains.
474      */
475     if(hres != S_OK) {
476         heap_free(host_name);
477         if(hres == E_FAIL)
478             return S_FALSE;
479         return hres;
480     }
481
482     /* First try CURRENT_USER. */
483     res = RegOpenKeyW(HKEY_CURRENT_USER, wszZoneMapDomainsKey, &domains);
484     if(res == ERROR_SUCCESS) {
485         hres = search_for_domain_mapping(domains, schema, host_name, host_len, zone);
486         RegCloseKey(domains);
487     } else
488         WARN("Failed to open HKCU's %s key\n", debugstr_w(wszZoneMapDomainsKey));
489
490     /* If that doesn't work try LOCAL_MACHINE. */
491     if(hres == S_FALSE) {
492         res = RegOpenKeyW(HKEY_LOCAL_MACHINE, wszZoneMapDomainsKey, &domains);
493         if(res == ERROR_SUCCESS) {
494             hres = search_for_domain_mapping(domains, schema, host_name, host_len, zone);
495             RegCloseKey(domains);
496         } else
497             WARN("Failed to open HKLM's %s key\n", debugstr_w(wszZoneMapDomainsKey));
498     }
499
500     heap_free(host_name);
501     return hres;
502 }
503
504 static HRESULT map_url_to_zone(LPCWSTR url, DWORD *zone, LPWSTR *ret_url)
505 {
506     LPWSTR secur_url;
507     WCHAR schema[64];
508     DWORD size=0;
509     HRESULT hres;
510
511     *zone = URLZONE_INVALID;
512
513     hres = CoInternetGetSecurityUrl(url, &secur_url, PSU_SECURITY_URL_ONLY, 0);
514     if(hres != S_OK) {
515         size = strlenW(url)*sizeof(WCHAR);
516
517         secur_url = heap_alloc(size);
518         if(!secur_url)
519             return E_OUTOFMEMORY;
520
521         memcpy(secur_url, url, size);
522     }
523
524     hres = CoInternetParseUrl(secur_url, PARSE_SCHEMA, 0, schema, sizeof(schema)/sizeof(WCHAR), &size, 0);
525     if(FAILED(hres) || !*schema) {
526         heap_free(secur_url);
527         return E_INVALIDARG;
528     }
529
530     /* file protocol is a special case */
531     if(!strcmpW(schema, fileW)) {
532         WCHAR path[MAX_PATH], root[20];
533         WCHAR *ptr;
534
535         hres = CoInternetParseUrl(secur_url, PARSE_PATH_FROM_URL, 0, path,
536                 sizeof(path)/sizeof(WCHAR), &size, 0);
537
538         if(SUCCEEDED(hres) && (ptr = strchrW(path, '\\')) && ptr-path < sizeof(root)/sizeof(WCHAR)) {
539             UINT type;
540
541             memcpy(root, path, (ptr-path)*sizeof(WCHAR));
542             root[ptr-path] = 0;
543
544             type = GetDriveTypeW(root);
545
546             switch(type) {
547             case DRIVE_UNKNOWN:
548             case DRIVE_NO_ROOT_DIR:
549                 break;
550             case DRIVE_REMOVABLE:
551             case DRIVE_FIXED:
552             case DRIVE_CDROM:
553             case DRIVE_RAMDISK:
554                 *zone = URLZONE_LOCAL_MACHINE;
555                 hres = S_OK;
556                 break;
557             case DRIVE_REMOTE:
558                 *zone = URLZONE_INTERNET;
559                 hres = S_OK;
560                 break;
561             default:
562                 FIXME("unsupported drive type %d\n", type);
563             }
564         }
565     }
566
567     if(*zone == URLZONE_INVALID) {
568         hres = get_zone_from_domains(secur_url, schema, zone);
569         if(hres == S_FALSE)
570             hres = get_zone_from_reg(schema, zone);
571     }
572
573     if(FAILED(hres) || !ret_url)
574         heap_free(secur_url);
575     else
576         *ret_url = secur_url;
577
578     return hres;
579 }
580
581 static HRESULT open_zone_key(HKEY parent_key, DWORD zone, HKEY *hkey)
582 {
583     static const WCHAR wszFormat[] = {'%','s','%','u',0};
584
585     WCHAR key_name[sizeof(wszZonesKey)/sizeof(WCHAR)+12];
586     DWORD res;
587
588     wsprintfW(key_name, wszFormat, wszZonesKey, zone);
589
590     res = RegOpenKeyW(parent_key, key_name, hkey);
591
592     if(res != ERROR_SUCCESS) {
593         WARN("RegOpenKey failed\n");
594         return E_INVALIDARG;
595     }
596
597     return S_OK;
598 }
599
600 static HRESULT get_action_policy(DWORD zone, DWORD action, BYTE *policy, DWORD size, URLZONEREG zone_reg)
601 {
602     HKEY parent_key;
603     HKEY hkey;
604     LONG res;
605     HRESULT hres;
606
607     switch(action) {
608     case URLACTION_SCRIPT_OVERRIDE_SAFETY:
609     case URLACTION_ACTIVEX_OVERRIDE_SCRIPT_SAFETY:
610         *(DWORD*)policy = URLPOLICY_DISALLOW;
611         return S_OK;
612     }
613
614     switch(zone_reg) {
615     case URLZONEREG_DEFAULT:
616     case URLZONEREG_HKCU:
617         parent_key = HKEY_CURRENT_USER;
618         break;
619     case URLZONEREG_HKLM:
620         parent_key = HKEY_LOCAL_MACHINE;
621         break;
622     default:
623         WARN("Unknown URLZONEREG: %d\n", zone_reg);
624         return E_FAIL;
625     };
626
627     hres = open_zone_key(parent_key, zone, &hkey);
628     if(SUCCEEDED(hres)) {
629         WCHAR action_str[16];
630         DWORD len = size;
631
632         static const WCHAR formatW[] = {'%','X',0};
633
634         wsprintfW(action_str, formatW, action);
635
636         res = RegQueryValueExW(hkey, action_str, NULL, NULL, policy, &len);
637         if(res == ERROR_MORE_DATA) {
638             hres = E_INVALIDARG;
639         }else if(res == ERROR_FILE_NOT_FOUND) {
640             hres = E_FAIL;
641         }else if(res != ERROR_SUCCESS) {
642             ERR("RegQueryValue failed: %d\n", res);
643             hres = E_UNEXPECTED;
644         }
645
646         RegCloseKey(hkey);
647     }
648
649     if(FAILED(hres) && zone_reg == URLZONEREG_DEFAULT)
650         return get_action_policy(zone, action, policy, size, URLZONEREG_HKLM);
651
652     return hres;
653 }
654
655 /***********************************************************************
656  *           InternetSecurityManager implementation
657  *
658  */
659 typedef struct {
660     IInternetSecurityManagerEx2 IInternetSecurityManagerEx2_iface;
661
662     LONG ref;
663
664     IInternetSecurityMgrSite *mgrsite;
665     IInternetSecurityManager *custom_manager;
666 } SecManagerImpl;
667
668 static inline SecManagerImpl *impl_from_IInternetSecurityManagerEx2(IInternetSecurityManagerEx2 *iface)
669 {
670     return CONTAINING_RECORD(iface, SecManagerImpl, IInternetSecurityManagerEx2_iface);
671 }
672
673 static HRESULT WINAPI SecManagerImpl_QueryInterface(IInternetSecurityManagerEx2* iface,REFIID riid,void** ppvObject)
674 {
675     SecManagerImpl *This = impl_from_IInternetSecurityManagerEx2(iface);
676
677     TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppvObject);
678
679     /* Perform a sanity check on the parameters.*/
680     if ( (This==0) || (ppvObject==0) )
681         return E_INVALIDARG;
682
683     /* Initialize the return parameter */
684     *ppvObject = 0;
685
686     /* Compare the riid with the interface IDs implemented by this object.*/
687     if (IsEqualIID(&IID_IUnknown, riid) ||
688         IsEqualIID(&IID_IInternetSecurityManager, riid) ||
689         IsEqualIID(&IID_IInternetSecurityManagerEx, riid) ||
690         IsEqualIID(&IID_IInternetSecurityManagerEx2, riid))
691         *ppvObject = iface;
692
693     /* Check that we obtained an interface.*/
694     if (!*ppvObject) {
695         WARN("not supported interface %s\n", debugstr_guid(riid));
696         return E_NOINTERFACE;
697     }
698
699     /* Query Interface always increases the reference count by one when it is successful */
700     IInternetSecurityManager_AddRef(iface);
701
702     return S_OK;
703 }
704
705 static ULONG WINAPI SecManagerImpl_AddRef(IInternetSecurityManagerEx2* iface)
706 {
707     SecManagerImpl *This = impl_from_IInternetSecurityManagerEx2(iface);
708     ULONG refCount = InterlockedIncrement(&This->ref);
709
710     TRACE("(%p) ref=%u\n", This, refCount);
711
712     return refCount;
713 }
714
715 static ULONG WINAPI SecManagerImpl_Release(IInternetSecurityManagerEx2* iface)
716 {
717     SecManagerImpl *This = impl_from_IInternetSecurityManagerEx2(iface);
718     ULONG refCount = InterlockedDecrement(&This->ref);
719
720     TRACE("(%p) ref=%u\n", This, refCount);
721
722     /* destroy the object if there's no more reference on it */
723     if (!refCount){
724         if(This->mgrsite)
725             IInternetSecurityMgrSite_Release(This->mgrsite);
726         if(This->custom_manager)
727             IInternetSecurityManager_Release(This->custom_manager);
728
729         heap_free(This);
730
731         URLMON_UnlockModule();
732     }
733
734     return refCount;
735 }
736
737 static HRESULT WINAPI SecManagerImpl_SetSecuritySite(IInternetSecurityManagerEx2 *iface,
738                                                      IInternetSecurityMgrSite *pSite)
739 {
740     SecManagerImpl *This = impl_from_IInternetSecurityManagerEx2(iface);
741
742     TRACE("(%p)->(%p)\n", This, pSite);
743
744     if(This->mgrsite)
745         IInternetSecurityMgrSite_Release(This->mgrsite);
746
747     if(This->custom_manager) {
748         IInternetSecurityManager_Release(This->custom_manager);
749         This->custom_manager = NULL;
750     }
751
752     This->mgrsite = pSite;
753
754     if(pSite) {
755         IServiceProvider *servprov;
756         HRESULT hres;
757
758         IInternetSecurityMgrSite_AddRef(pSite);
759
760         hres = IInternetSecurityMgrSite_QueryInterface(pSite, &IID_IServiceProvider,
761                 (void**)&servprov);
762         if(SUCCEEDED(hres)) {
763             IServiceProvider_QueryService(servprov, &SID_SInternetSecurityManager,
764                     &IID_IInternetSecurityManager, (void**)&This->custom_manager);
765             IServiceProvider_Release(servprov);
766         }
767     }
768
769     return S_OK;
770 }
771
772 static HRESULT WINAPI SecManagerImpl_GetSecuritySite(IInternetSecurityManagerEx2 *iface,
773                                                      IInternetSecurityMgrSite **ppSite)
774 {
775     SecManagerImpl *This = impl_from_IInternetSecurityManagerEx2(iface);
776
777     TRACE("(%p)->(%p)\n", This, ppSite);
778
779     if(!ppSite)
780         return E_INVALIDARG;
781
782     if(This->mgrsite)
783         IInternetSecurityMgrSite_AddRef(This->mgrsite);
784
785     *ppSite = This->mgrsite;
786     return S_OK;
787 }
788
789 static HRESULT WINAPI SecManagerImpl_MapUrlToZone(IInternetSecurityManagerEx2 *iface,
790                                                   LPCWSTR pwszUrl, DWORD *pdwZone,
791                                                   DWORD dwFlags)
792 {
793     SecManagerImpl *This = impl_from_IInternetSecurityManagerEx2(iface);
794     HRESULT hres;
795
796     TRACE("(%p)->(%s %p %08x)\n", iface, debugstr_w(pwszUrl), pdwZone, dwFlags);
797
798     if(This->custom_manager) {
799         hres = IInternetSecurityManager_MapUrlToZone(This->custom_manager,
800                 pwszUrl, pdwZone, dwFlags);
801         if(hres != INET_E_DEFAULT_ACTION)
802             return hres;
803     }
804
805     if(!pwszUrl) {
806         *pdwZone = URLZONE_INVALID;
807         return E_INVALIDARG;
808     }
809
810     if(dwFlags)
811         FIXME("not supported flags: %08x\n", dwFlags);
812
813     return map_url_to_zone(pwszUrl, pdwZone, NULL);
814 }
815
816 static HRESULT WINAPI SecManagerImpl_GetSecurityId(IInternetSecurityManagerEx2 *iface,
817         LPCWSTR pwszUrl, BYTE *pbSecurityId, DWORD *pcbSecurityId, DWORD_PTR dwReserved)
818 {
819     SecManagerImpl *This = impl_from_IInternetSecurityManagerEx2(iface);
820     LPWSTR url, ptr, ptr2;
821     DWORD zone, len;
822     HRESULT hres;
823
824     static const WCHAR wszFile[] = {'f','i','l','e',':'};
825
826     TRACE("(%p)->(%s %p %p %08lx)\n", iface, debugstr_w(pwszUrl), pbSecurityId,
827           pcbSecurityId, dwReserved);
828
829     if(This->custom_manager) {
830         hres = IInternetSecurityManager_GetSecurityId(This->custom_manager,
831                 pwszUrl, pbSecurityId, pcbSecurityId, dwReserved);
832         if(hres != INET_E_DEFAULT_ACTION)
833             return hres;
834     }
835
836     if(!pwszUrl || !pbSecurityId || !pcbSecurityId)
837         return E_INVALIDARG;
838
839     if(dwReserved)
840         FIXME("dwReserved is not supported\n");
841
842     hres = map_url_to_zone(pwszUrl, &zone, &url);
843     if(FAILED(hres))
844         return hres == 0x80041001 ? E_INVALIDARG : hres;
845
846     /* file protocol is a special case */
847     if(strlenW(url) >= sizeof(wszFile)/sizeof(WCHAR)
848             && !memcmp(url, wszFile, sizeof(wszFile)) && strchrW(url, '\\')) {
849
850         static const BYTE secidFile[] = {'f','i','l','e',':'};
851
852         heap_free(url);
853
854         if(*pcbSecurityId < sizeof(secidFile)+sizeof(zone))
855             return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
856
857         memcpy(pbSecurityId, secidFile, sizeof(secidFile));
858         *(DWORD*)(pbSecurityId+sizeof(secidFile)) = zone;
859
860         *pcbSecurityId = sizeof(secidFile)+sizeof(zone);
861         return S_OK;
862     }
863
864     ptr = strchrW(url, ':');
865     ptr2 = ++ptr;
866     while(*ptr2 == '/')
867         ptr2++;
868     if(ptr2 != ptr)
869         memmove(ptr, ptr2, (strlenW(ptr2)+1)*sizeof(WCHAR));
870
871     ptr = strchrW(ptr, '/');
872     if(ptr)
873         *ptr = 0;
874
875     len = WideCharToMultiByte(CP_ACP, 0, url, -1, NULL, 0, NULL, NULL)-1;
876
877     if(len+sizeof(DWORD) > *pcbSecurityId) {
878         heap_free(url);
879         return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
880     }
881
882     WideCharToMultiByte(CP_ACP, 0, url, -1, (LPSTR)pbSecurityId, len, NULL, NULL);
883     heap_free(url);
884
885     *(DWORD*)(pbSecurityId+len) = zone;
886
887     *pcbSecurityId = len+sizeof(DWORD);
888
889     return S_OK;
890 }
891
892
893 static HRESULT WINAPI SecManagerImpl_ProcessUrlAction(IInternetSecurityManagerEx2 *iface,
894                                                       LPCWSTR pwszUrl, DWORD dwAction,
895                                                       BYTE *pPolicy, DWORD cbPolicy,
896                                                       BYTE *pContext, DWORD cbContext,
897                                                       DWORD dwFlags, DWORD dwReserved)
898 {
899     SecManagerImpl *This = impl_from_IInternetSecurityManagerEx2(iface);
900     DWORD zone, policy;
901     HRESULT hres;
902
903     TRACE("(%p)->(%s %08x %p %08x %p %08x %08x %08x)\n", iface, debugstr_w(pwszUrl), dwAction,
904           pPolicy, cbPolicy, pContext, cbContext, dwFlags, dwReserved);
905
906     if(This->custom_manager) {
907         hres = IInternetSecurityManager_ProcessUrlAction(This->custom_manager, pwszUrl, dwAction,
908                 pPolicy, cbPolicy, pContext, cbContext, dwFlags, dwReserved);
909         if(hres != INET_E_DEFAULT_ACTION)
910             return hres;
911     }
912
913     if(dwFlags || dwReserved)
914         FIXME("Unsupported arguments\n");
915
916     if(!pwszUrl)
917         return E_INVALIDARG;
918
919     hres = map_url_to_zone(pwszUrl, &zone, NULL);
920     if(FAILED(hres))
921         return hres;
922
923     hres = get_action_policy(zone, dwAction, (BYTE*)&policy, sizeof(policy), URLZONEREG_DEFAULT);
924     if(FAILED(hres))
925         return hres;
926
927     TRACE("policy %x\n", policy);
928     if(cbPolicy >= sizeof(DWORD))
929         *(DWORD*)pPolicy = policy;
930
931     switch(GetUrlPolicyPermissions(policy)) {
932     case URLPOLICY_ALLOW:
933     case URLPOLICY_CHANNEL_SOFTDIST_PRECACHE:
934         return S_OK;
935     case URLPOLICY_DISALLOW:
936         return S_FALSE;
937     case URLPOLICY_QUERY:
938         FIXME("URLPOLICY_QUERY not implemented\n");
939         return E_FAIL;
940     default:
941         FIXME("Not implemented policy %x\n", policy);
942     }
943
944     return E_FAIL;
945 }
946                                                
947
948 static HRESULT WINAPI SecManagerImpl_QueryCustomPolicy(IInternetSecurityManagerEx2 *iface,
949                                                        LPCWSTR pwszUrl, REFGUID guidKey,
950                                                        BYTE **ppPolicy, DWORD *pcbPolicy,
951                                                        BYTE *pContext, DWORD cbContext,
952                                                        DWORD dwReserved)
953 {
954     SecManagerImpl *This = impl_from_IInternetSecurityManagerEx2(iface);
955     HRESULT hres;
956
957     TRACE("(%p)->(%s %s %p %p %p %08x %08x )\n", iface, debugstr_w(pwszUrl), debugstr_guid(guidKey),
958           ppPolicy, pcbPolicy, pContext, cbContext, dwReserved);
959
960     if(This->custom_manager) {
961         hres = IInternetSecurityManager_QueryCustomPolicy(This->custom_manager, pwszUrl, guidKey,
962                 ppPolicy, pcbPolicy, pContext, cbContext, dwReserved);
963         if(hres != INET_E_DEFAULT_ACTION)
964             return hres;
965     }
966
967     WARN("Unknown guidKey %s\n", debugstr_guid(guidKey));
968     return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
969 }
970
971 static HRESULT WINAPI SecManagerImpl_SetZoneMapping(IInternetSecurityManagerEx2 *iface,
972                                                     DWORD dwZone, LPCWSTR pwszPattern, DWORD dwFlags)
973 {
974     SecManagerImpl *This = impl_from_IInternetSecurityManagerEx2(iface);
975     HRESULT hres;
976
977     TRACE("(%p)->(%08x %s %08x)\n", iface, dwZone, debugstr_w(pwszPattern),dwFlags);
978
979     if(This->custom_manager) {
980         hres = IInternetSecurityManager_SetZoneMapping(This->custom_manager, dwZone,
981                 pwszPattern, dwFlags);
982         if(hres != INET_E_DEFAULT_ACTION)
983             return hres;
984     }
985
986     FIXME("Default action is not implemented\n");
987     return E_NOTIMPL;
988 }
989
990 static HRESULT WINAPI SecManagerImpl_GetZoneMappings(IInternetSecurityManagerEx2 *iface,
991         DWORD dwZone, IEnumString **ppenumString, DWORD dwFlags)
992 {
993     SecManagerImpl *This = impl_from_IInternetSecurityManagerEx2(iface);
994     HRESULT hres;
995
996     TRACE("(%p)->(%08x %p %08x)\n", iface, dwZone, ppenumString,dwFlags);
997
998     if(This->custom_manager) {
999         hres = IInternetSecurityManager_GetZoneMappings(This->custom_manager, dwZone,
1000                 ppenumString, dwFlags);
1001         if(hres != INET_E_DEFAULT_ACTION)
1002             return hres;
1003     }
1004
1005     FIXME("Default action is not implemented\n");
1006     return E_NOTIMPL;
1007 }
1008
1009 static HRESULT WINAPI SecManagerImpl_ProcessUrlActionEx(IInternetSecurityManagerEx2 *iface,
1010         LPCWSTR pwszUrl, DWORD dwAction, BYTE *pPolicy, DWORD cbPolicy, BYTE *pContext, DWORD cbContext,
1011         DWORD dwFlags, DWORD dwReserved, DWORD *pdwOutFlags)
1012 {
1013     SecManagerImpl *This = impl_from_IInternetSecurityManagerEx2(iface);
1014     FIXME("(%p)->(%s %08x %p %d %p %d %08x %08x %p) stub\n", This, debugstr_w(pwszUrl), dwAction, pPolicy, cbPolicy,
1015           pContext, cbContext, dwFlags, dwReserved, pdwOutFlags);
1016     return E_NOTIMPL;
1017 }
1018
1019 static HRESULT WINAPI SecManagerImpl_MapUrlToZoneEx2(IInternetSecurityManagerEx2 *iface,
1020         IUri *pUri, DWORD *pdwZone, DWORD dwFlags, LPWSTR *ppwszMappedUrl, DWORD *pdwOutFlags)
1021 {
1022     SecManagerImpl *This = impl_from_IInternetSecurityManagerEx2(iface);
1023     FIXME("(%p)->(%p %p %08x %p %p) stub\n", This, pUri, pdwZone, dwFlags, ppwszMappedUrl, pdwOutFlags);
1024     return E_NOTIMPL;
1025 }
1026
1027 static HRESULT WINAPI SecManagerImpl_ProcessUrlActionEx2(IInternetSecurityManagerEx2 *iface,
1028         IUri *pUri, DWORD dwAction, BYTE *pPolicy, DWORD cbPolicy, BYTE *pContext, DWORD cbContext,
1029         DWORD dwFlags, DWORD_PTR dwReserved, DWORD *pdwOutFlags)
1030 {
1031     SecManagerImpl *This = impl_from_IInternetSecurityManagerEx2(iface);
1032     FIXME("(%p)->(%p %08x %p %d %p %d %08x %08x %p) stub\n", This, pUri, dwAction, pPolicy,
1033           cbPolicy, pContext, cbContext, dwFlags, (DWORD)dwReserved, pdwOutFlags);
1034     return E_NOTIMPL;
1035 }
1036
1037 static HRESULT WINAPI SecManagerImpl_GetSecurityIdEx2(IInternetSecurityManagerEx2 *iface,
1038         IUri *pUri, BYTE *pbSecurityId, DWORD *pcbSecurityId, DWORD_PTR dwReserved)
1039 {
1040     SecManagerImpl *This = impl_from_IInternetSecurityManagerEx2(iface);
1041     FIXME("(%p)->(%p %p %p %08x) stub\n", This, pUri, pbSecurityId, pcbSecurityId, (DWORD)dwReserved);
1042     return E_NOTIMPL;
1043 }
1044
1045 static HRESULT WINAPI SecManagerImpl_QueryCustomPolicyEx2(IInternetSecurityManagerEx2 *iface,
1046         IUri *pUri, REFGUID guidKey, BYTE **ppPolicy, DWORD *pcbPolicy, BYTE *pContext,
1047         DWORD cbContext, DWORD_PTR dwReserved)
1048 {
1049     SecManagerImpl *This = impl_from_IInternetSecurityManagerEx2(iface);
1050     FIXME("(%p)->(%p %s %p %p %p %d %08x) stub\n", This, pUri, debugstr_guid(guidKey), ppPolicy, pcbPolicy,
1051           pContext, cbContext, (DWORD)dwReserved);
1052     return E_NOTIMPL;
1053 }
1054
1055 static const IInternetSecurityManagerEx2Vtbl VT_SecManagerImpl =
1056 {
1057     SecManagerImpl_QueryInterface,
1058     SecManagerImpl_AddRef,
1059     SecManagerImpl_Release,
1060     SecManagerImpl_SetSecuritySite,
1061     SecManagerImpl_GetSecuritySite,
1062     SecManagerImpl_MapUrlToZone,
1063     SecManagerImpl_GetSecurityId,
1064     SecManagerImpl_ProcessUrlAction,
1065     SecManagerImpl_QueryCustomPolicy,
1066     SecManagerImpl_SetZoneMapping,
1067     SecManagerImpl_GetZoneMappings,
1068     SecManagerImpl_ProcessUrlActionEx,
1069     SecManagerImpl_MapUrlToZoneEx2,
1070     SecManagerImpl_ProcessUrlActionEx2,
1071     SecManagerImpl_GetSecurityIdEx2,
1072     SecManagerImpl_QueryCustomPolicyEx2
1073 };
1074
1075 HRESULT SecManagerImpl_Construct(IUnknown *pUnkOuter, LPVOID *ppobj)
1076 {
1077     SecManagerImpl *This;
1078
1079     TRACE("(%p,%p)\n",pUnkOuter,ppobj);
1080     This = heap_alloc(sizeof(*This));
1081
1082     /* Initialize the virtual function table. */
1083     This->IInternetSecurityManagerEx2_iface.lpVtbl = &VT_SecManagerImpl;
1084
1085     This->ref = 1;
1086     This->mgrsite = NULL;
1087     This->custom_manager = NULL;
1088
1089     *ppobj = This;
1090
1091     URLMON_LockModule();
1092
1093     return S_OK;
1094 }
1095
1096 /***********************************************************************
1097  *           InternetZoneManager implementation
1098  *
1099  */
1100 typedef struct {
1101     IInternetZoneManagerEx2 IInternetZoneManagerEx2_iface;
1102     LONG ref;
1103     LPDWORD *zonemaps;
1104     DWORD zonemap_count;
1105 } ZoneMgrImpl;
1106
1107 static inline ZoneMgrImpl *impl_from_IInternetZoneManagerEx2(IInternetZoneManagerEx2 *iface)
1108 {
1109     return CONTAINING_RECORD(iface, ZoneMgrImpl, IInternetZoneManagerEx2_iface);
1110 }
1111
1112
1113 /***********************************************************************
1114  * build_zonemap_from_reg [internal]
1115  *
1116  * Enumerate the Zones in the Registry and return the Zones in a DWORD-array
1117  * The number of the Zones is returned in data[0]
1118  */
1119 static LPDWORD build_zonemap_from_reg(void)
1120 {
1121     WCHAR name[32];
1122     HKEY hkey;
1123     LPDWORD data = NULL;
1124     DWORD allocated = 6; /* space for the zonecount and Zone "0" up to Zone "4" */
1125     DWORD used = 0;
1126     DWORD res;
1127     DWORD len;
1128
1129
1130     res = RegOpenKeyW(HKEY_CURRENT_USER, wszZonesKey, &hkey);
1131     if (res)
1132         return NULL;
1133
1134     data = heap_alloc(allocated * sizeof(DWORD));
1135     if (!data)
1136         goto cleanup;
1137
1138     while (!res) {
1139         name[0] = '\0';
1140         len = sizeof(name) / sizeof(name[0]);
1141         res = RegEnumKeyExW(hkey, used, name, &len, NULL, NULL, NULL, NULL);
1142
1143         if (!res) {
1144             used++;
1145             if (used == allocated) {
1146                 LPDWORD new_data;
1147
1148                 allocated *= 2;
1149                 new_data = heap_realloc_zero(data, allocated * sizeof(DWORD));
1150                 if (!new_data)
1151                     goto cleanup;
1152
1153                 data = new_data;
1154             }
1155             data[used] = atoiW(name);
1156         }
1157     }
1158     if (used) {
1159         RegCloseKey(hkey);
1160         data[0] = used;
1161         return data;
1162     }
1163
1164 cleanup:
1165     /* something failed */
1166     RegCloseKey(hkey);
1167     heap_free(data);
1168     return NULL;
1169 }
1170
1171 /********************************************************************
1172  *      IInternetZoneManager_QueryInterface
1173  */
1174 static HRESULT WINAPI ZoneMgrImpl_QueryInterface(IInternetZoneManagerEx2* iface, REFIID riid, void** ppvObject)
1175 {
1176     ZoneMgrImpl* This = impl_from_IInternetZoneManagerEx2(iface);
1177
1178     TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(riid), ppvObject);
1179
1180     if(!This || !ppvObject)
1181         return E_INVALIDARG;
1182
1183     if(IsEqualIID(&IID_IUnknown, riid)) {
1184         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppvObject);
1185     }else if(IsEqualIID(&IID_IInternetZoneManager, riid)) {
1186         TRACE("(%p)->(IID_InternetZoneManager %p)\n", This, ppvObject);
1187     }else if(IsEqualIID(&IID_IInternetZoneManagerEx, riid)) {
1188         TRACE("(%p)->(IID_InternetZoneManagerEx %p)\n", This, ppvObject);
1189     }else if(IsEqualIID(&IID_IInternetZoneManagerEx2, riid)) {
1190         TRACE("(%p)->(IID_InternetZoneManagerEx2 %p)\n", This, ppvObject);
1191     }
1192     else
1193     {
1194         FIXME("Unknown interface: %s\n", debugstr_guid(riid));
1195         *ppvObject = NULL;
1196         return E_NOINTERFACE;
1197     }
1198
1199     *ppvObject = iface;
1200     IInternetZoneManager_AddRef(iface);
1201     return S_OK;
1202 }
1203
1204 /********************************************************************
1205  *      IInternetZoneManager_AddRef
1206  */
1207 static ULONG WINAPI ZoneMgrImpl_AddRef(IInternetZoneManagerEx2* iface)
1208 {
1209     ZoneMgrImpl* This = impl_from_IInternetZoneManagerEx2(iface);
1210     ULONG refCount = InterlockedIncrement(&This->ref);
1211
1212     TRACE("(%p)->(ref before=%u)\n",This, refCount - 1);
1213
1214     return refCount;
1215 }
1216
1217 /********************************************************************
1218  *      IInternetZoneManager_Release
1219  */
1220 static ULONG WINAPI ZoneMgrImpl_Release(IInternetZoneManagerEx2* iface)
1221 {
1222     ZoneMgrImpl* This = impl_from_IInternetZoneManagerEx2(iface);
1223     ULONG refCount = InterlockedDecrement(&This->ref);
1224
1225     TRACE("(%p)->(ref before=%u)\n",This, refCount + 1);
1226
1227     if(!refCount) {
1228         while (This->zonemap_count) heap_free(This->zonemaps[--This->zonemap_count]);
1229         heap_free(This->zonemaps);
1230         heap_free(This);
1231         URLMON_UnlockModule();
1232     }
1233     
1234     return refCount;
1235 }
1236
1237 /********************************************************************
1238  *      IInternetZoneManager_GetZoneAttributes
1239  */
1240 static HRESULT WINAPI ZoneMgrImpl_GetZoneAttributes(IInternetZoneManagerEx2* iface,
1241                                                     DWORD dwZone,
1242                                                     ZONEATTRIBUTES* pZoneAttributes)
1243 {
1244     ZoneMgrImpl* This = impl_from_IInternetZoneManagerEx2(iface);
1245     HRESULT hr;
1246     HKEY hcu;
1247     HKEY hklm = NULL;
1248
1249     TRACE("(%p)->(%d %p)\n", This, dwZone, pZoneAttributes);
1250
1251     if (!pZoneAttributes)
1252         return E_INVALIDARG;
1253
1254     hr = open_zone_key(HKEY_CURRENT_USER, dwZone, &hcu);
1255     if (FAILED(hr))
1256         return S_OK;  /* IE6 and older returned E_FAIL here */
1257
1258     hr = open_zone_key(HKEY_LOCAL_MACHINE, dwZone, &hklm);
1259     if (FAILED(hr))
1260         TRACE("Zone %d not in HKLM\n", dwZone);
1261
1262     get_string_from_reg(hcu, hklm, displaynameW, pZoneAttributes->szDisplayName, MAX_ZONE_PATH);
1263     get_string_from_reg(hcu, hklm, descriptionW, pZoneAttributes->szDescription, MAX_ZONE_DESCRIPTION);
1264     get_string_from_reg(hcu, hklm, iconW, pZoneAttributes->szIconPath, MAX_ZONE_PATH);
1265     get_dword_from_reg(hcu, hklm, minlevelW, &pZoneAttributes->dwTemplateMinLevel);
1266     get_dword_from_reg(hcu, hklm, currentlevelW, &pZoneAttributes->dwTemplateCurrentLevel);
1267     get_dword_from_reg(hcu, hklm, recommendedlevelW, &pZoneAttributes->dwTemplateRecommended);
1268     get_dword_from_reg(hcu, hklm, flagsW, &pZoneAttributes->dwFlags);
1269
1270     RegCloseKey(hklm);
1271     RegCloseKey(hcu);
1272     return S_OK;
1273 }
1274
1275 /********************************************************************
1276  *      IInternetZoneManager_SetZoneAttributes
1277  */
1278 static HRESULT WINAPI ZoneMgrImpl_SetZoneAttributes(IInternetZoneManagerEx2* iface,
1279                                                     DWORD dwZone,
1280                                                     ZONEATTRIBUTES* pZoneAttributes)
1281 {
1282     ZoneMgrImpl* This = impl_from_IInternetZoneManagerEx2(iface);
1283     HRESULT hr;
1284     HKEY hcu;
1285
1286     TRACE("(%p)->(%d %p)\n", This, dwZone, pZoneAttributes);
1287
1288     if (!pZoneAttributes)
1289         return E_INVALIDARG;
1290
1291     hr = open_zone_key(HKEY_CURRENT_USER, dwZone, &hcu);
1292     if (FAILED(hr))
1293         return S_OK;  /* IE6 returned E_FAIL here */
1294
1295     /* cbSize is ignored */
1296     RegSetValueExW(hcu, displaynameW, 0, REG_SZ, (LPBYTE) pZoneAttributes->szDisplayName,
1297                     (lstrlenW(pZoneAttributes->szDisplayName)+1)* sizeof(WCHAR));
1298
1299     RegSetValueExW(hcu, descriptionW, 0, REG_SZ, (LPBYTE) pZoneAttributes->szDescription,
1300                     (lstrlenW(pZoneAttributes->szDescription)+1)* sizeof(WCHAR));
1301
1302     RegSetValueExW(hcu, iconW, 0, REG_SZ, (LPBYTE) pZoneAttributes->szIconPath,
1303                     (lstrlenW(pZoneAttributes->szIconPath)+1)* sizeof(WCHAR));
1304
1305     RegSetValueExW(hcu, minlevelW, 0, REG_DWORD,
1306                     (const BYTE*) &pZoneAttributes->dwTemplateMinLevel, sizeof(DWORD));
1307
1308     RegSetValueExW(hcu, currentlevelW, 0, REG_DWORD,
1309                     (const BYTE*) &pZoneAttributes->dwTemplateCurrentLevel, sizeof(DWORD));
1310
1311     RegSetValueExW(hcu, recommendedlevelW, 0, REG_DWORD,
1312                     (const BYTE*) &pZoneAttributes->dwTemplateRecommended, sizeof(DWORD));
1313
1314     RegSetValueExW(hcu, flagsW, 0, REG_DWORD, (const BYTE*) &pZoneAttributes->dwFlags, sizeof(DWORD));
1315     RegCloseKey(hcu);
1316     return S_OK;
1317
1318 }
1319
1320 /********************************************************************
1321  *      IInternetZoneManager_GetZoneCustomPolicy
1322  */
1323 static HRESULT WINAPI ZoneMgrImpl_GetZoneCustomPolicy(IInternetZoneManagerEx2* iface,
1324                                                       DWORD dwZone,
1325                                                       REFGUID guidKey,
1326                                                       BYTE** ppPolicy,
1327                                                       DWORD* pcbPolicy,
1328                                                       URLZONEREG ulrZoneReg)
1329 {
1330     FIXME("(%p)->(%08x %s %p %p %08x) stub\n", iface, dwZone, debugstr_guid(guidKey),
1331                                                     ppPolicy, pcbPolicy, ulrZoneReg);
1332     return E_NOTIMPL;
1333 }
1334
1335 /********************************************************************
1336  *      IInternetZoneManager_SetZoneCustomPolicy
1337  */
1338 static HRESULT WINAPI ZoneMgrImpl_SetZoneCustomPolicy(IInternetZoneManagerEx2* iface,
1339                                                       DWORD dwZone,
1340                                                       REFGUID guidKey,
1341                                                       BYTE* ppPolicy,
1342                                                       DWORD cbPolicy,
1343                                                       URLZONEREG ulrZoneReg)
1344 {
1345     FIXME("(%p)->(%08x %s %p %08x %08x) stub\n", iface, dwZone, debugstr_guid(guidKey),
1346                                                     ppPolicy, cbPolicy, ulrZoneReg);
1347     return E_NOTIMPL;
1348 }
1349
1350 /********************************************************************
1351  *      IInternetZoneManager_GetZoneActionPolicy
1352  */
1353 static HRESULT WINAPI ZoneMgrImpl_GetZoneActionPolicy(IInternetZoneManagerEx2* iface,
1354         DWORD dwZone, DWORD dwAction, BYTE* pPolicy, DWORD cbPolicy, URLZONEREG urlZoneReg)
1355 {
1356     TRACE("(%p)->(%d %08x %p %d %d)\n", iface, dwZone, dwAction, pPolicy,
1357             cbPolicy, urlZoneReg);
1358
1359     if(!pPolicy)
1360         return E_INVALIDARG;
1361
1362     return get_action_policy(dwZone, dwAction, pPolicy, cbPolicy, urlZoneReg);
1363 }
1364
1365 /********************************************************************
1366  *      IInternetZoneManager_SetZoneActionPolicy
1367  */
1368 static HRESULT WINAPI ZoneMgrImpl_SetZoneActionPolicy(IInternetZoneManagerEx2* iface,
1369                                                       DWORD dwZone,
1370                                                       DWORD dwAction,
1371                                                       BYTE* pPolicy,
1372                                                       DWORD cbPolicy,
1373                                                       URLZONEREG urlZoneReg)
1374 {
1375     FIXME("(%p)->(%08x %08x %p %08x %08x) stub\n", iface, dwZone, dwAction, pPolicy,
1376                                                        cbPolicy, urlZoneReg);
1377     return E_NOTIMPL;
1378 }
1379
1380 /********************************************************************
1381  *      IInternetZoneManager_PromptAction
1382  */
1383 static HRESULT WINAPI ZoneMgrImpl_PromptAction(IInternetZoneManagerEx2* iface,
1384                                                DWORD dwAction,
1385                                                HWND hwndParent,
1386                                                LPCWSTR pwszUrl,
1387                                                LPCWSTR pwszText,
1388                                                DWORD dwPromptFlags)
1389 {
1390     FIXME("%p %08x %p %s %s %08x\n", iface, dwAction, hwndParent,
1391           debugstr_w(pwszUrl), debugstr_w(pwszText), dwPromptFlags );
1392     return E_NOTIMPL;
1393 }
1394
1395 /********************************************************************
1396  *      IInternetZoneManager_LogAction
1397  */
1398 static HRESULT WINAPI ZoneMgrImpl_LogAction(IInternetZoneManagerEx2* iface,
1399                                             DWORD dwAction,
1400                                             LPCWSTR pwszUrl,
1401                                             LPCWSTR pwszText,
1402                                             DWORD dwLogFlags)
1403 {
1404     FIXME("(%p)->(%08x %s %s %08x) stub\n", iface, dwAction, debugstr_w(pwszUrl),
1405                                               debugstr_w(pwszText), dwLogFlags);
1406     return E_NOTIMPL;
1407 }
1408
1409 /********************************************************************
1410  *      IInternetZoneManager_CreateZoneEnumerator
1411  */
1412 static HRESULT WINAPI ZoneMgrImpl_CreateZoneEnumerator(IInternetZoneManagerEx2* iface,
1413                                                        DWORD* pdwEnum,
1414                                                        DWORD* pdwCount,
1415                                                        DWORD dwFlags)
1416 {
1417     ZoneMgrImpl* This = impl_from_IInternetZoneManagerEx2(iface);
1418     LPDWORD * new_maps;
1419     LPDWORD data;
1420     DWORD i;
1421
1422     TRACE("(%p)->(%p, %p, 0x%08x)\n", This, pdwEnum, pdwCount, dwFlags);
1423     if (!pdwEnum || !pdwCount || (dwFlags != 0))
1424         return E_INVALIDARG;
1425
1426     data = build_zonemap_from_reg();
1427     TRACE("found %d zones\n", data ? data[0] : -1);
1428
1429     if (!data)
1430         return E_FAIL;
1431
1432     for (i = 0; i < This->zonemap_count; i++) {
1433         if (This->zonemaps && !This->zonemaps[i]) {
1434             This->zonemaps[i] = data;
1435             *pdwEnum = i;
1436             *pdwCount = data[0];
1437             return S_OK;
1438         }
1439     }
1440
1441     if (This->zonemaps) {
1442         /* try to double the nr. of pointers in the array */
1443         new_maps = heap_realloc_zero(This->zonemaps, This->zonemap_count * 2 * sizeof(LPDWORD));
1444         if (new_maps)
1445             This->zonemap_count *= 2;
1446     }
1447     else
1448     {
1449         This->zonemap_count = 2;
1450         new_maps = heap_alloc_zero(This->zonemap_count * sizeof(LPDWORD));
1451     }
1452
1453     if (!new_maps) {
1454         heap_free(data);
1455         return E_FAIL;
1456     }
1457     This->zonemaps = new_maps;
1458     This->zonemaps[i] = data;
1459     *pdwEnum = i;
1460     *pdwCount = data[0];
1461     return S_OK;
1462 }
1463
1464 /********************************************************************
1465  *      IInternetZoneManager_GetZoneAt
1466  */
1467 static HRESULT WINAPI ZoneMgrImpl_GetZoneAt(IInternetZoneManagerEx2* iface,
1468                                             DWORD dwEnum,
1469                                             DWORD dwIndex,
1470                                             DWORD* pdwZone)
1471 {
1472     ZoneMgrImpl* This = impl_from_IInternetZoneManagerEx2(iface);
1473     LPDWORD data;
1474
1475     TRACE("(%p)->(0x%08x, %d, %p)\n", This, dwEnum, dwIndex, pdwZone);
1476
1477     /* make sure, that dwEnum and dwIndex are in the valid range */
1478     if (dwEnum < This->zonemap_count) {
1479         if ((data = This->zonemaps[dwEnum])) {
1480             if (dwIndex < data[0]) {
1481                 *pdwZone = data[dwIndex + 1];
1482                 return S_OK;
1483             }
1484         }
1485     }
1486     return E_INVALIDARG;
1487 }
1488
1489 /********************************************************************
1490  *      IInternetZoneManager_DestroyZoneEnumerator
1491  */
1492 static HRESULT WINAPI ZoneMgrImpl_DestroyZoneEnumerator(IInternetZoneManagerEx2* iface,
1493                                                         DWORD dwEnum)
1494 {
1495     ZoneMgrImpl* This = impl_from_IInternetZoneManagerEx2(iface);
1496     LPDWORD data;
1497
1498     TRACE("(%p)->(0x%08x)\n", This, dwEnum);
1499     /* make sure, that dwEnum is valid */
1500     if (dwEnum < This->zonemap_count) {
1501         if ((data = This->zonemaps[dwEnum])) {
1502             This->zonemaps[dwEnum] = NULL;
1503             heap_free(data);
1504             return S_OK;
1505         }
1506     }
1507     return E_INVALIDARG;
1508 }
1509
1510 /********************************************************************
1511  *      IInternetZoneManager_CopyTemplatePoliciesToZone
1512  */
1513 static HRESULT WINAPI ZoneMgrImpl_CopyTemplatePoliciesToZone(IInternetZoneManagerEx2* iface,
1514                                                              DWORD dwTemplate,
1515                                                              DWORD dwZone,
1516                                                              DWORD dwReserved)
1517 {
1518     FIXME("(%p)->(%08x %08x %08x) stub\n", iface, dwTemplate, dwZone, dwReserved);
1519     return E_NOTIMPL;
1520 }
1521
1522 /********************************************************************
1523  *      IInternetZoneManagerEx_GetZoneActionPolicyEx
1524  */
1525 static HRESULT WINAPI ZoneMgrImpl_GetZoneActionPolicyEx(IInternetZoneManagerEx2* iface,
1526                                                         DWORD dwZone,
1527                                                         DWORD dwAction,
1528                                                         BYTE* pPolicy,
1529                                                         DWORD cbPolicy,
1530                                                         URLZONEREG urlZoneReg,
1531                                                         DWORD dwFlags)
1532 {
1533     TRACE("(%p)->(%d, 0x%x, %p, %d, %d, 0x%x)\n", iface, dwZone,
1534             dwAction, pPolicy, cbPolicy, urlZoneReg, dwFlags);
1535
1536     if(!pPolicy)
1537         return E_INVALIDARG;
1538
1539     if (dwFlags)
1540         FIXME("dwFlags 0x%x ignored\n", dwFlags);
1541
1542     return get_action_policy(dwZone, dwAction, pPolicy, cbPolicy, urlZoneReg);
1543 }
1544
1545 /********************************************************************
1546  *      IInternetZoneManagerEx_SetZoneActionPolicyEx
1547  */
1548 static HRESULT WINAPI ZoneMgrImpl_SetZoneActionPolicyEx(IInternetZoneManagerEx2* iface,
1549                                                         DWORD dwZone,
1550                                                         DWORD dwAction,
1551                                                         BYTE* pPolicy,
1552                                                         DWORD cbPolicy,
1553                                                         URLZONEREG urlZoneReg,
1554                                                         DWORD dwFlags)
1555 {
1556     FIXME("(%p)->(%d, 0x%x, %p, %d, %d, 0x%x) stub\n", iface, dwZone, dwAction, pPolicy,
1557                                                        cbPolicy, urlZoneReg, dwFlags);
1558     return E_NOTIMPL;
1559 }
1560
1561 /********************************************************************
1562  *      IInternetZoneManagerEx2_GetZoneAttributesEx
1563  */
1564 static HRESULT WINAPI ZoneMgrImpl_GetZoneAttributesEx(IInternetZoneManagerEx2* iface,
1565                                                       DWORD dwZone,
1566                                                       ZONEATTRIBUTES* pZoneAttributes,
1567                                                       DWORD dwFlags)
1568 {
1569     TRACE("(%p)->(%d, %p, 0x%x)\n", iface, dwZone, pZoneAttributes, dwFlags);
1570
1571     if (dwFlags)
1572         FIXME("dwFlags 0x%x ignored\n", dwFlags);
1573
1574     return IInternetZoneManager_GetZoneAttributes(iface, dwZone, pZoneAttributes);
1575 }
1576
1577
1578 /********************************************************************
1579  *      IInternetZoneManagerEx2_GetZoneSecurityState
1580  */
1581 static HRESULT WINAPI ZoneMgrImpl_GetZoneSecurityState(IInternetZoneManagerEx2* iface,
1582                                                        DWORD dwZoneIndex,
1583                                                        BOOL fRespectPolicy,
1584                                                        LPDWORD pdwState,
1585                                                        BOOL *pfPolicyEncountered)
1586 {
1587     FIXME("(%p)->(%d, %d, %p, %p) stub\n", iface, dwZoneIndex, fRespectPolicy,
1588                                            pdwState, pfPolicyEncountered);
1589
1590     *pdwState = SECURITY_IE_STATE_GREEN;
1591
1592     if (pfPolicyEncountered)
1593         *pfPolicyEncountered = FALSE;
1594
1595     return S_OK;
1596 }
1597
1598 /********************************************************************
1599  *      IInternetZoneManagerEx2_GetIESecurityState
1600  */
1601 static HRESULT WINAPI ZoneMgrImpl_GetIESecurityState(IInternetZoneManagerEx2* iface,
1602                                                      BOOL fRespectPolicy,
1603                                                      LPDWORD pdwState,
1604                                                      BOOL *pfPolicyEncountered,
1605                                                      BOOL fNoCache)
1606 {
1607     FIXME("(%p)->(%d, %p, %p, %d) stub\n", iface, fRespectPolicy, pdwState,
1608                                            pfPolicyEncountered, fNoCache);
1609
1610     *pdwState = SECURITY_IE_STATE_GREEN;
1611
1612     if (pfPolicyEncountered)
1613         *pfPolicyEncountered = FALSE;
1614
1615     return S_OK;
1616 }
1617
1618 /********************************************************************
1619  *      IInternetZoneManagerEx2_FixInsecureSettings
1620  */
1621 static HRESULT WINAPI ZoneMgrImpl_FixInsecureSettings(IInternetZoneManagerEx2* iface)
1622 {
1623     FIXME("(%p) stub\n", iface);
1624     return S_OK;
1625 }
1626
1627 /********************************************************************
1628  *      IInternetZoneManager_Construct
1629  */
1630 static const IInternetZoneManagerEx2Vtbl ZoneMgrImplVtbl = {
1631     ZoneMgrImpl_QueryInterface,
1632     ZoneMgrImpl_AddRef,
1633     ZoneMgrImpl_Release,
1634     /* IInternetZoneManager */
1635     ZoneMgrImpl_GetZoneAttributes,
1636     ZoneMgrImpl_SetZoneAttributes,
1637     ZoneMgrImpl_GetZoneCustomPolicy,
1638     ZoneMgrImpl_SetZoneCustomPolicy,
1639     ZoneMgrImpl_GetZoneActionPolicy,
1640     ZoneMgrImpl_SetZoneActionPolicy,
1641     ZoneMgrImpl_PromptAction,
1642     ZoneMgrImpl_LogAction,
1643     ZoneMgrImpl_CreateZoneEnumerator,
1644     ZoneMgrImpl_GetZoneAt,
1645     ZoneMgrImpl_DestroyZoneEnumerator,
1646     ZoneMgrImpl_CopyTemplatePoliciesToZone,
1647     /* IInternetZoneManagerEx */
1648     ZoneMgrImpl_GetZoneActionPolicyEx,
1649     ZoneMgrImpl_SetZoneActionPolicyEx,
1650     /* IInternetZoneManagerEx2 */
1651     ZoneMgrImpl_GetZoneAttributesEx,
1652     ZoneMgrImpl_GetZoneSecurityState,
1653     ZoneMgrImpl_GetIESecurityState,
1654     ZoneMgrImpl_FixInsecureSettings,
1655 };
1656
1657 HRESULT ZoneMgrImpl_Construct(IUnknown *pUnkOuter, LPVOID *ppobj)
1658 {
1659     ZoneMgrImpl* ret = heap_alloc_zero(sizeof(ZoneMgrImpl));
1660
1661     TRACE("(%p %p)\n", pUnkOuter, ppobj);
1662     ret->IInternetZoneManagerEx2_iface.lpVtbl = &ZoneMgrImplVtbl;
1663     ret->ref = 1;
1664     *ppobj = (IInternetZoneManagerEx*)ret;
1665
1666     URLMON_LockModule();
1667
1668     return S_OK;
1669 }
1670
1671 /***********************************************************************
1672  *           CoInternetCreateSecurityManager (URLMON.@)
1673  *
1674  */
1675 HRESULT WINAPI CoInternetCreateSecurityManager( IServiceProvider *pSP,
1676     IInternetSecurityManager **ppSM, DWORD dwReserved )
1677 {
1678     TRACE("%p %p %d\n", pSP, ppSM, dwReserved );
1679
1680     if(pSP)
1681         FIXME("pSP not supported\n");
1682
1683     return SecManagerImpl_Construct(NULL, (void**) ppSM);
1684 }
1685
1686 /********************************************************************
1687  *      CoInternetCreateZoneManager (URLMON.@)
1688  */
1689 HRESULT WINAPI CoInternetCreateZoneManager(IServiceProvider* pSP, IInternetZoneManager** ppZM, DWORD dwReserved)
1690 {
1691     TRACE("(%p %p %x)\n", pSP, ppZM, dwReserved);
1692     return ZoneMgrImpl_Construct(NULL, (void**)ppZM);
1693 }
1694
1695 static HRESULT parse_security_url(const WCHAR *url, PSUACTION action, WCHAR **result) {
1696     IInternetProtocolInfo *protocol_info;
1697     WCHAR *tmp, *new_url = NULL, *alloc_url = NULL;
1698     DWORD size, new_size;
1699     HRESULT hres = S_OK, parse_hres;
1700
1701     while(1) {
1702         TRACE("parsing %s\n", debugstr_w(url));
1703
1704         protocol_info = get_protocol_info(url);
1705         if(!protocol_info)
1706             break;
1707
1708         size = strlenW(url)+1;
1709         new_url = CoTaskMemAlloc(size*sizeof(WCHAR));
1710         if(!new_url) {
1711             hres = E_OUTOFMEMORY;
1712             break;
1713         }
1714
1715         new_size = 0;
1716         parse_hres = IInternetProtocolInfo_ParseUrl(protocol_info, url, PARSE_SECURITY_URL, 0, new_url, size, &new_size, 0);
1717         if(parse_hres == S_FALSE) {
1718             if(!new_size) {
1719                 hres = E_UNEXPECTED;
1720                 break;
1721             }
1722
1723             tmp = CoTaskMemRealloc(new_url, new_size*sizeof(WCHAR));
1724             if(!tmp) {
1725                 hres = E_OUTOFMEMORY;
1726                 break;
1727             }
1728             new_url = tmp;
1729             parse_hres = IInternetProtocolInfo_ParseUrl(protocol_info, url, PARSE_SECURITY_URL, 0, new_url,
1730                     new_size, &new_size, 0);
1731             if(parse_hres == S_FALSE) {
1732                 hres = E_FAIL;
1733                 break;
1734             }
1735         }
1736
1737         if(parse_hres != S_OK || !strcmpW(url, new_url))
1738             break;
1739
1740         CoTaskMemFree(alloc_url);
1741         url = alloc_url = new_url;
1742         new_url = NULL;
1743     }
1744
1745     CoTaskMemFree(new_url);
1746
1747     if(hres != S_OK) {
1748         WARN("failed: %08x\n", hres);
1749         CoTaskMemFree(alloc_url);
1750         return hres;
1751     }
1752
1753     if(action == PSU_DEFAULT && (protocol_info = get_protocol_info(url))) {
1754         size = strlenW(url)+1;
1755         new_url = CoTaskMemAlloc(size * sizeof(WCHAR));
1756         if(new_url) {
1757             new_size = 0;
1758             parse_hres = IInternetProtocolInfo_ParseUrl(protocol_info, url, PARSE_SECURITY_DOMAIN, 0,
1759                     new_url, size, &new_size, 0);
1760             if(parse_hres == S_FALSE) {
1761                 if(new_size) {
1762                     tmp = CoTaskMemRealloc(new_url, new_size*sizeof(WCHAR));
1763                     if(tmp) {
1764                         new_url = tmp;
1765                         parse_hres = IInternetProtocolInfo_ParseUrl(protocol_info, url, PARSE_SECURITY_DOMAIN, 0, new_url,
1766                                 new_size, &new_size, 0);
1767                         if(parse_hres == S_FALSE)
1768                             hres = E_FAIL;
1769                     }else {
1770                         hres = E_OUTOFMEMORY;
1771                     }
1772                 }else {
1773                     hres = E_UNEXPECTED;
1774                 }
1775             }
1776
1777             if(hres == S_OK && parse_hres == S_OK) {
1778                 CoTaskMemFree(alloc_url);
1779                 url = alloc_url = new_url;
1780                 new_url = NULL;
1781             }
1782
1783             CoTaskMemFree(new_url);
1784         }else {
1785             hres = E_OUTOFMEMORY;
1786         }
1787         IInternetProtocolInfo_Release(protocol_info);
1788     }
1789
1790     if(FAILED(hres)) {
1791         WARN("failed %08x\n", hres);
1792         CoTaskMemFree(alloc_url);
1793         return hres;
1794     }
1795
1796     if(!alloc_url) {
1797         size = strlenW(url)+1;
1798         alloc_url = CoTaskMemAlloc(size * sizeof(WCHAR));
1799         if(!alloc_url)
1800             return E_OUTOFMEMORY;
1801         memcpy(alloc_url, url, size * sizeof(WCHAR));
1802     }
1803
1804     *result = alloc_url;
1805     return S_OK;
1806 }
1807
1808 /********************************************************************
1809  *      CoInternetGetSecurityUrl (URLMON.@)
1810  */
1811 HRESULT WINAPI CoInternetGetSecurityUrl(LPCWSTR pwzUrl, LPWSTR *ppwzSecUrl, PSUACTION psuAction, DWORD dwReserved)
1812 {
1813     WCHAR *secure_url;
1814     HRESULT hres;
1815
1816     TRACE("(%p,%p,%u,%u)\n", pwzUrl, ppwzSecUrl, psuAction, dwReserved);
1817
1818     hres = parse_security_url(pwzUrl, psuAction, &secure_url);
1819     if(FAILED(hres))
1820         return hres;
1821
1822     if(psuAction != PSU_SECURITY_URL_ONLY) {
1823         PARSEDURLW parsed_url = { sizeof(parsed_url) };
1824         DWORD size;
1825
1826         /* FIXME: Use helpers from uri.c */
1827         if(SUCCEEDED(ParseURLW(secure_url, &parsed_url))) {
1828             WCHAR *new_url;
1829
1830             switch(parsed_url.nScheme) {
1831             case URL_SCHEME_FTP:
1832             case URL_SCHEME_HTTP:
1833             case URL_SCHEME_HTTPS:
1834                 size = strlenW(secure_url)+1;
1835                 new_url = CoTaskMemAlloc(size * sizeof(WCHAR));
1836                 if(new_url)
1837                     hres = UrlGetPartW(secure_url, new_url, &size, URL_PART_HOSTNAME, URL_PARTFLAG_KEEPSCHEME);
1838                 else
1839                     hres = E_OUTOFMEMORY;
1840                 CoTaskMemFree(secure_url);
1841                 if(hres != S_OK) {
1842                     WARN("UrlGetPart failed: %08x\n", hres);
1843                     CoTaskMemFree(new_url);
1844                     return FAILED(hres) ? hres : E_FAIL;
1845                 }
1846                 secure_url = new_url;
1847             }
1848         }
1849     }
1850
1851     *ppwzSecUrl = secure_url;
1852     return S_OK;
1853 }
1854
1855 /********************************************************************
1856  *      CoInternetGetSecurityUrlEx (URLMON.@)
1857  */
1858 HRESULT WINAPI CoInternetGetSecurityUrlEx(IUri *pUri, IUri **ppSecUri, PSUACTION psuAction, DWORD_PTR dwReserved)
1859 {
1860     URL_SCHEME scheme_type;
1861     BSTR secure_uri;
1862     WCHAR *ret_url;
1863     HRESULT hres;
1864
1865     TRACE("(%p,%p,%u,%u)\n", pUri, ppSecUri, psuAction, (DWORD)dwReserved);
1866
1867     if(!pUri || !ppSecUri)
1868         return E_INVALIDARG;
1869
1870     hres = IUri_GetDisplayUri(pUri, &secure_uri);
1871     if(FAILED(hres))
1872         return hres;
1873
1874     hres = parse_security_url(secure_uri, psuAction, &ret_url);
1875     SysFreeString(secure_uri);
1876     if(FAILED(hres))
1877         return hres;
1878
1879     /* File URIs have to hierarchical. */
1880     hres = IUri_GetScheme(pUri, (DWORD*)&scheme_type);
1881     if(SUCCEEDED(hres) && scheme_type == URL_SCHEME_FILE) {
1882         const WCHAR *tmp = ret_url;
1883
1884         /* Check and see if a "//" is after the scheme name. */
1885         tmp += sizeof(fileW)/sizeof(WCHAR);
1886         if(*tmp != '/' || *(tmp+1) != '/')
1887             hres = E_INVALIDARG;
1888     }
1889
1890     if(SUCCEEDED(hres))
1891         hres = CreateUri(ret_url, Uri_CREATE_ALLOW_IMPLICIT_WILDCARD_SCHEME, 0, ppSecUri);
1892     CoTaskMemFree(ret_url);
1893     return hres;
1894 }