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