urlmon: Call remove_dot_segments on path opaque for mk: protocol.
[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  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22
23 #include <stdio.h>
24
25 #include "urlmon_main.h"
26 #include "winreg.h"
27 #include "wininet.h"
28
29 #define NO_SHLWAPI_REG
30 #include "shlwapi.h"
31
32 #include "wine/debug.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
35
36 static const WCHAR currentlevelW[] = {'C','u','r','r','e','n','t','L','e','v','e','l',0};
37 static const WCHAR descriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
38 static const WCHAR displaynameW[] = {'D','i','s','p','l','a','y','N','a','m','e',0};
39 static const WCHAR fileW[] = {'f','i','l','e',0};
40 static const WCHAR flagsW[] = {'F','l','a','g','s',0};
41 static const WCHAR iconW[] = {'I','c','o','n',0};
42 static const WCHAR minlevelW[] = {'M','i','n','L','e','v','e','l',0};
43 static const WCHAR recommendedlevelW[] = {'R','e','c','o','m','m','e','n','d','e','d',
44                                           'L','e','v','e','l',0};
45 static const WCHAR wszZonesKey[] = {'S','o','f','t','w','a','r','e','\\',
46                                     'M','i','c','r','o','s','o','f','t','\\',
47                                     'W','i','n','d','o','w','s','\\',
48                                     'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
49                                     'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s','\\',
50                                     'Z','o','n','e','s','\\',0};
51
52 /********************************************************************
53  * get_string_from_reg [internal]
54  *
55  * helper to get a string from the reg.
56  *
57  */
58 static void get_string_from_reg(HKEY hcu, HKEY hklm, LPCWSTR name, LPWSTR out, DWORD maxlen)
59 {
60     DWORD type = REG_SZ;
61     DWORD len = maxlen * sizeof(WCHAR);
62     DWORD res;
63
64     res = RegQueryValueExW(hcu, name, NULL, &type, (LPBYTE) out, &len);
65
66     if (res && hklm) {
67         len = maxlen * sizeof(WCHAR);
68         type = REG_SZ;
69         res = RegQueryValueExW(hklm, name, NULL, &type, (LPBYTE) out, &len);
70     }
71
72     if (res) {
73         TRACE("%s failed: %d\n", debugstr_w(name), res);
74         *out = '\0';
75     }
76 }
77
78 /********************************************************************
79  * get_dword_from_reg [internal]
80  *
81  * helper to get a dword from the reg.
82  *
83  */
84 static void get_dword_from_reg(HKEY hcu, HKEY hklm, LPCWSTR name, LPDWORD out)
85 {
86     DWORD type = REG_DWORD;
87     DWORD len = sizeof(DWORD);
88     DWORD res;
89
90     res = RegQueryValueExW(hcu, name, NULL, &type, (LPBYTE) out, &len);
91
92     if (res && hklm) {
93         len = sizeof(DWORD);
94         type = REG_DWORD;
95         res = RegQueryValueExW(hklm, name, NULL, &type, (LPBYTE) out, &len);
96     }
97
98     if (res) {
99         TRACE("%s failed: %d\n", debugstr_w(name), res);
100         *out = 0;
101     }
102 }
103
104 static HRESULT get_zone_from_reg(LPCWSTR schema, DWORD *zone)
105 {
106     DWORD res, size;
107     HKEY hkey;
108
109     static const WCHAR wszZoneMapProtocolKey[] =
110         {'S','o','f','t','w','a','r','e','\\',
111          'M','i','c','r','o','s','o','f','t','\\',
112          'W','i','n','d','o','w','s','\\',
113          'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
114          'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s','\\',
115          'Z','o','n','e','M','a','p','\\',
116          'P','r','o','t','o','c','o','l','D','e','f','a','u','l','t','s',0};
117
118     res = RegOpenKeyW(HKEY_CURRENT_USER, wszZoneMapProtocolKey, &hkey);
119     if(res != ERROR_SUCCESS) {
120         ERR("Could not open key %s\n", debugstr_w(wszZoneMapProtocolKey));
121         return E_UNEXPECTED;
122     }
123
124     size = sizeof(DWORD);
125     res = RegQueryValueExW(hkey, schema, NULL, NULL, (PBYTE)zone, &size);
126     RegCloseKey(hkey);
127     if(res == ERROR_SUCCESS)
128         return S_OK;
129
130     res = RegOpenKeyW(HKEY_LOCAL_MACHINE, wszZoneMapProtocolKey, &hkey);
131     if(res != ERROR_SUCCESS) {
132         ERR("Could not open key %s\n", debugstr_w(wszZoneMapProtocolKey));
133         return E_UNEXPECTED;
134     }
135
136     size = sizeof(DWORD);
137     res = RegQueryValueExW(hkey, schema, NULL, NULL, (PBYTE)zone, &size);
138     RegCloseKey(hkey);
139     if(res == ERROR_SUCCESS)
140         return S_OK;
141
142     *zone = 3;
143     return S_OK;
144 }
145
146 static HRESULT map_url_to_zone(LPCWSTR url, DWORD *zone, LPWSTR *ret_url)
147 {
148     LPWSTR secur_url;
149     WCHAR schema[64];
150     DWORD size=0;
151     HRESULT hres;
152
153     *zone = -1;
154
155     hres = CoInternetGetSecurityUrl(url, &secur_url, PSU_SECURITY_URL_ONLY, 0);
156     if(hres != S_OK) {
157         size = strlenW(url)*sizeof(WCHAR);
158
159         secur_url = heap_alloc(size);
160         if(!secur_url)
161             return E_OUTOFMEMORY;
162
163         memcpy(secur_url, url, size);
164     }
165
166     hres = CoInternetParseUrl(secur_url, PARSE_SCHEMA, 0, schema, sizeof(schema)/sizeof(WCHAR), &size, 0);
167     if(FAILED(hres) || !*schema) {
168         heap_free(secur_url);
169         return E_INVALIDARG;
170     }
171
172     /* file protocol is a special case */
173     if(!strcmpW(schema, fileW)) {
174         WCHAR path[MAX_PATH], root[20];
175         WCHAR *ptr;
176
177         hres = CoInternetParseUrl(secur_url, PARSE_PATH_FROM_URL, 0, path,
178                 sizeof(path)/sizeof(WCHAR), &size, 0);
179
180         if(SUCCEEDED(hres) && (ptr = strchrW(path, '\\')) && ptr-path < sizeof(root)/sizeof(WCHAR)) {
181             UINT type;
182
183             memcpy(root, path, (ptr-path)*sizeof(WCHAR));
184             root[ptr-path] = 0;
185
186             type = GetDriveTypeW(root);
187
188             switch(type) {
189             case DRIVE_UNKNOWN:
190             case DRIVE_NO_ROOT_DIR:
191                 break;
192             case DRIVE_REMOVABLE:
193             case DRIVE_FIXED:
194             case DRIVE_CDROM:
195             case DRIVE_RAMDISK:
196                 *zone = 0;
197                 hres = S_OK;
198                 break;
199             case DRIVE_REMOTE:
200                 *zone = 3;
201                 hres = S_OK;
202                 break;
203             default:
204                 FIXME("unsupported drive type %d\n", type);
205             }
206         }
207     }
208
209     if(*zone == -1) {
210         WARN("domains are not yet implemented\n");
211         hres = get_zone_from_reg(schema, zone);
212     }
213
214     if(FAILED(hres) || !ret_url)
215         heap_free(secur_url);
216     else
217         *ret_url = secur_url;
218
219     return hres;
220 }
221
222 static HRESULT open_zone_key(HKEY parent_key, DWORD zone, HKEY *hkey)
223 {
224     static const WCHAR wszFormat[] = {'%','s','%','l','d',0};
225
226     WCHAR key_name[sizeof(wszZonesKey)/sizeof(WCHAR)+8];
227     DWORD res;
228
229     wsprintfW(key_name, wszFormat, wszZonesKey, zone);
230
231     res = RegOpenKeyW(parent_key, key_name, hkey);
232
233     if(res != ERROR_SUCCESS) {
234         WARN("RegOpenKey failed\n");
235         return E_INVALIDARG;
236     }
237
238     return S_OK;
239 }
240
241 static HRESULT get_action_policy(DWORD zone, DWORD action, BYTE *policy, DWORD size, URLZONEREG zone_reg)
242 {
243     HKEY parent_key;
244     HKEY hkey;
245     LONG res;
246     HRESULT hres;
247
248     switch(action) {
249     case URLACTION_SCRIPT_OVERRIDE_SAFETY:
250     case URLACTION_ACTIVEX_OVERRIDE_SCRIPT_SAFETY:
251         *(DWORD*)policy = URLPOLICY_DISALLOW;
252         return S_OK;
253     }
254
255     switch(zone_reg) {
256     case URLZONEREG_DEFAULT:
257     case URLZONEREG_HKCU:
258         parent_key = HKEY_CURRENT_USER;
259         break;
260     case URLZONEREG_HKLM:
261         parent_key = HKEY_LOCAL_MACHINE;
262         break;
263     default:
264         WARN("Unknown URLZONEREG: %d\n", zone_reg);
265         return E_FAIL;
266     };
267
268     hres = open_zone_key(parent_key, zone, &hkey);
269     if(SUCCEEDED(hres)) {
270         WCHAR action_str[16];
271         DWORD len = size;
272
273         static const WCHAR formatW[] = {'%','X',0};
274
275         wsprintfW(action_str, formatW, action);
276
277         res = RegQueryValueExW(hkey, action_str, NULL, NULL, policy, &len);
278         if(res == ERROR_MORE_DATA) {
279             hres = E_INVALIDARG;
280         }else if(res == ERROR_FILE_NOT_FOUND) {
281             hres = E_FAIL;
282         }else if(res != ERROR_SUCCESS) {
283             ERR("RegQueryValue failed: %d\n", res);
284             hres = E_UNEXPECTED;
285         }
286
287         RegCloseKey(hkey);
288     }
289
290     if(FAILED(hres) && zone_reg == URLZONEREG_DEFAULT)
291         return get_action_policy(zone, action, policy, size, URLZONEREG_HKLM);
292
293     return hres;
294 }
295
296 static HRESULT parse_security_uri(IUri *uri, PSUACTION action, IUri **result) {
297     WCHAR buf1[INTERNET_MAX_URL_LENGTH], buf2[INTERNET_MAX_URL_LENGTH];
298     LPWSTR url, tmp;
299     HRESULT hres;
300     DWORD len = 0;
301     BOOL use_url = FALSE;
302
303     url = buf1;
304     tmp = buf2;
305     *result = NULL;
306
307     hres = IUri_GetPropertyLength(uri, Uri_PROPERTY_ABSOLUTE_URI, &len, 0);
308     if(FAILED(hres))
309         return hres;
310
311     hres = CoInternetParseIUri(uri, PARSE_SECURITY_URL, 0, url, len+1, &len, 0);
312     if(hres == S_OK) {
313         use_url = TRUE;
314         while(TRUE) {
315             hres = CoInternetParseUrl(url, PARSE_SECURITY_URL, 0, tmp, len+1, &len, 0);
316             if(hres != S_OK || !strcmpW(url, tmp))
317                 break;
318
319             if(url == buf1) {
320                 url = buf2;
321                 tmp = buf1;
322             } else {
323                 url = buf1;
324                 tmp = buf2;
325             }
326         }
327     }
328
329     if(action == PSU_DEFAULT) {
330         if(use_url) {
331             hres = CoInternetParseUrl(url, PARSE_SECURITY_DOMAIN, 0, tmp, len+1, &len, 0);
332             url = tmp;
333         } else {
334             hres = CoInternetParseIUri(uri, PARSE_SECURITY_DOMAIN, 0, url, len+1, &len, 0);
335             if(hres == S_OK)
336                 use_url = TRUE;
337         }
338     }
339
340     if(use_url) {
341         hres = CreateUri(url, 0, 0, result);
342         if(FAILED(hres))
343             return hres;
344     }
345
346     return S_OK;
347 }
348
349 /***********************************************************************
350  *           InternetSecurityManager implementation
351  *
352  */
353 typedef struct {
354     IInternetSecurityManager IInternetSecurityManager_iface;
355
356     LONG ref;
357
358     IInternetSecurityMgrSite *mgrsite;
359     IInternetSecurityManager *custom_manager;
360 } SecManagerImpl;
361
362 static inline SecManagerImpl *impl_from_IInternetSecurityManager(IInternetSecurityManager *iface)
363 {
364     return CONTAINING_RECORD(iface, SecManagerImpl, IInternetSecurityManager_iface);
365 }
366
367 static HRESULT WINAPI SecManagerImpl_QueryInterface(IInternetSecurityManager* iface,REFIID riid,void** ppvObject)
368 {
369     SecManagerImpl *This = impl_from_IInternetSecurityManager(iface);
370
371     TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppvObject);
372
373     /* Perform a sanity check on the parameters.*/
374     if ( (This==0) || (ppvObject==0) )
375         return E_INVALIDARG;
376
377     /* Initialize the return parameter */
378     *ppvObject = 0;
379
380     /* Compare the riid with the interface IDs implemented by this object.*/
381     if (IsEqualIID(&IID_IUnknown, riid) ||
382         IsEqualIID(&IID_IInternetSecurityManager, riid))
383         *ppvObject = iface;
384
385     /* Check that we obtained an interface.*/
386     if (!*ppvObject) {
387         WARN("not supported interface %s\n", debugstr_guid(riid));
388         return E_NOINTERFACE;
389     }
390
391     /* Query Interface always increases the reference count by one when it is successful */
392     IInternetSecurityManager_AddRef(iface);
393
394     return S_OK;
395 }
396
397 static ULONG WINAPI SecManagerImpl_AddRef(IInternetSecurityManager* iface)
398 {
399     SecManagerImpl *This = impl_from_IInternetSecurityManager(iface);
400     ULONG refCount = InterlockedIncrement(&This->ref);
401
402     TRACE("(%p) ref=%u\n", This, refCount);
403
404     return refCount;
405 }
406
407 static ULONG WINAPI SecManagerImpl_Release(IInternetSecurityManager* iface)
408 {
409     SecManagerImpl *This = impl_from_IInternetSecurityManager(iface);
410     ULONG refCount = InterlockedDecrement(&This->ref);
411
412     TRACE("(%p) ref=%u\n", This, refCount);
413
414     /* destroy the object if there's no more reference on it */
415     if (!refCount){
416         if(This->mgrsite)
417             IInternetSecurityMgrSite_Release(This->mgrsite);
418         if(This->custom_manager)
419             IInternetSecurityManager_Release(This->custom_manager);
420
421         heap_free(This);
422
423         URLMON_UnlockModule();
424     }
425
426     return refCount;
427 }
428
429 static HRESULT WINAPI SecManagerImpl_SetSecuritySite(IInternetSecurityManager *iface,
430                                                      IInternetSecurityMgrSite *pSite)
431 {
432     SecManagerImpl *This = impl_from_IInternetSecurityManager(iface);
433
434     TRACE("(%p)->(%p)\n", This, pSite);
435
436     if(This->mgrsite)
437         IInternetSecurityMgrSite_Release(This->mgrsite);
438
439     if(This->custom_manager) {
440         IInternetSecurityManager_Release(This->custom_manager);
441         This->custom_manager = NULL;
442     }
443
444     This->mgrsite = pSite;
445
446     if(pSite) {
447         IServiceProvider *servprov;
448         HRESULT hres;
449
450         IInternetSecurityMgrSite_AddRef(pSite);
451
452         hres = IInternetSecurityMgrSite_QueryInterface(pSite, &IID_IServiceProvider,
453                 (void**)&servprov);
454         if(SUCCEEDED(hres)) {
455             IServiceProvider_QueryService(servprov, &SID_SInternetSecurityManager,
456                     &IID_IInternetSecurityManager, (void**)&This->custom_manager);
457             IServiceProvider_Release(servprov);
458         }
459     }
460
461     return S_OK;
462 }
463
464 static HRESULT WINAPI SecManagerImpl_GetSecuritySite(IInternetSecurityManager *iface,
465                                                      IInternetSecurityMgrSite **ppSite)
466 {
467     SecManagerImpl *This = impl_from_IInternetSecurityManager(iface);
468
469     TRACE("(%p)->(%p)\n", This, ppSite);
470
471     if(!ppSite)
472         return E_INVALIDARG;
473
474     if(This->mgrsite)
475         IInternetSecurityMgrSite_AddRef(This->mgrsite);
476
477     *ppSite = This->mgrsite;
478     return S_OK;
479 }
480
481 static HRESULT WINAPI SecManagerImpl_MapUrlToZone(IInternetSecurityManager *iface,
482                                                   LPCWSTR pwszUrl, DWORD *pdwZone,
483                                                   DWORD dwFlags)
484 {
485     SecManagerImpl *This = impl_from_IInternetSecurityManager(iface);
486     HRESULT hres;
487
488     TRACE("(%p)->(%s %p %08x)\n", iface, debugstr_w(pwszUrl), pdwZone, dwFlags);
489
490     if(This->custom_manager) {
491         hres = IInternetSecurityManager_MapUrlToZone(This->custom_manager,
492                 pwszUrl, pdwZone, dwFlags);
493         if(hres != INET_E_DEFAULT_ACTION)
494             return hres;
495     }
496
497     if(!pwszUrl) {
498         *pdwZone = -1;
499         return E_INVALIDARG;
500     }
501
502     if(dwFlags)
503         FIXME("not supported flags: %08x\n", dwFlags);
504
505     return map_url_to_zone(pwszUrl, pdwZone, NULL);
506 }
507
508 static HRESULT WINAPI SecManagerImpl_GetSecurityId(IInternetSecurityManager *iface, 
509         LPCWSTR pwszUrl, BYTE *pbSecurityId, DWORD *pcbSecurityId, DWORD_PTR dwReserved)
510 {
511     SecManagerImpl *This = impl_from_IInternetSecurityManager(iface);
512     LPWSTR url, ptr, ptr2;
513     DWORD zone, len;
514     HRESULT hres;
515
516     static const WCHAR wszFile[] = {'f','i','l','e',':'};
517
518     TRACE("(%p)->(%s %p %p %08lx)\n", iface, debugstr_w(pwszUrl), pbSecurityId,
519           pcbSecurityId, dwReserved);
520
521     if(This->custom_manager) {
522         hres = IInternetSecurityManager_GetSecurityId(This->custom_manager,
523                 pwszUrl, pbSecurityId, pcbSecurityId, dwReserved);
524         if(hres != INET_E_DEFAULT_ACTION)
525             return hres;
526     }
527
528     if(!pwszUrl || !pbSecurityId || !pcbSecurityId)
529         return E_INVALIDARG;
530
531     if(dwReserved)
532         FIXME("dwReserved is not supported\n");
533
534     hres = map_url_to_zone(pwszUrl, &zone, &url);
535     if(FAILED(hres))
536         return hres == 0x80041001 ? E_INVALIDARG : hres;
537
538     /* file protocol is a special case */
539     if(strlenW(url) >= sizeof(wszFile)/sizeof(WCHAR)
540             && !memcmp(url, wszFile, sizeof(wszFile)) && strchrW(url, '\\')) {
541
542         static const BYTE secidFile[] = {'f','i','l','e',':'};
543
544         heap_free(url);
545
546         if(*pcbSecurityId < sizeof(secidFile)+sizeof(zone))
547             return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
548
549         memcpy(pbSecurityId, secidFile, sizeof(secidFile));
550         *(DWORD*)(pbSecurityId+sizeof(secidFile)) = zone;
551
552         *pcbSecurityId = sizeof(secidFile)+sizeof(zone);
553         return S_OK;
554     }
555
556     ptr = strchrW(url, ':');
557     ptr2 = ++ptr;
558     while(*ptr2 == '/')
559         ptr2++;
560     if(ptr2 != ptr)
561         memmove(ptr, ptr2, (strlenW(ptr2)+1)*sizeof(WCHAR));
562
563     ptr = strchrW(ptr, '/');
564     if(ptr)
565         *ptr = 0;
566
567     len = WideCharToMultiByte(CP_ACP, 0, url, -1, NULL, 0, NULL, NULL)-1;
568
569     if(len+sizeof(DWORD) > *pcbSecurityId) {
570         heap_free(url);
571         return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
572     }
573
574     WideCharToMultiByte(CP_ACP, 0, url, -1, (LPSTR)pbSecurityId, len, NULL, NULL);
575     heap_free(url);
576
577     *(DWORD*)(pbSecurityId+len) = zone;
578
579     *pcbSecurityId = len+sizeof(DWORD);
580
581     return S_OK;
582 }
583
584
585 static HRESULT WINAPI SecManagerImpl_ProcessUrlAction(IInternetSecurityManager *iface,
586                                                       LPCWSTR pwszUrl, DWORD dwAction,
587                                                       BYTE *pPolicy, DWORD cbPolicy,
588                                                       BYTE *pContext, DWORD cbContext,
589                                                       DWORD dwFlags, DWORD dwReserved)
590 {
591     SecManagerImpl *This = impl_from_IInternetSecurityManager(iface);
592     DWORD zone, policy;
593     HRESULT hres;
594
595     TRACE("(%p)->(%s %08x %p %08x %p %08x %08x %08x)\n", iface, debugstr_w(pwszUrl), dwAction,
596           pPolicy, cbPolicy, pContext, cbContext, dwFlags, dwReserved);
597
598     if(This->custom_manager) {
599         hres = IInternetSecurityManager_ProcessUrlAction(This->custom_manager, pwszUrl, dwAction,
600                 pPolicy, cbPolicy, pContext, cbContext, dwFlags, dwReserved);
601         if(hres != INET_E_DEFAULT_ACTION)
602             return hres;
603     }
604
605     if(dwFlags || dwReserved)
606         FIXME("Unsupported arguments\n");
607
608     if(!pwszUrl)
609         return E_INVALIDARG;
610
611     hres = map_url_to_zone(pwszUrl, &zone, NULL);
612     if(FAILED(hres))
613         return hres;
614
615     hres = get_action_policy(zone, dwAction, (BYTE*)&policy, sizeof(policy), URLZONEREG_DEFAULT);
616     if(FAILED(hres))
617         return hres;
618
619     TRACE("policy %x\n", policy);
620     if(cbPolicy >= sizeof(DWORD))
621         *(DWORD*)pPolicy = policy;
622
623     switch(GetUrlPolicyPermissions(policy)) {
624     case URLPOLICY_ALLOW:
625     case URLPOLICY_CHANNEL_SOFTDIST_PRECACHE:
626         return S_OK;
627     case URLPOLICY_DISALLOW:
628         return S_FALSE;
629     case URLPOLICY_QUERY:
630         FIXME("URLPOLICY_QUERY not implemented\n");
631         return E_FAIL;
632     default:
633         FIXME("Not implemented policy %x\n", policy);
634     }
635
636     return E_FAIL;
637 }
638                                                
639
640 static HRESULT WINAPI SecManagerImpl_QueryCustomPolicy(IInternetSecurityManager *iface,
641                                                        LPCWSTR pwszUrl, REFGUID guidKey,
642                                                        BYTE **ppPolicy, DWORD *pcbPolicy,
643                                                        BYTE *pContext, DWORD cbContext,
644                                                        DWORD dwReserved)
645 {
646     SecManagerImpl *This = impl_from_IInternetSecurityManager(iface);
647     HRESULT hres;
648
649     TRACE("(%p)->(%s %s %p %p %p %08x %08x )\n", iface, debugstr_w(pwszUrl), debugstr_guid(guidKey),
650           ppPolicy, pcbPolicy, pContext, cbContext, dwReserved);
651
652     if(This->custom_manager) {
653         hres = IInternetSecurityManager_QueryCustomPolicy(This->custom_manager, pwszUrl, guidKey,
654                 ppPolicy, pcbPolicy, pContext, cbContext, dwReserved);
655         if(hres != INET_E_DEFAULT_ACTION)
656             return hres;
657     }
658
659     WARN("Unknown guidKey %s\n", debugstr_guid(guidKey));
660     return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
661 }
662
663 static HRESULT WINAPI SecManagerImpl_SetZoneMapping(IInternetSecurityManager *iface,
664                                                     DWORD dwZone, LPCWSTR pwszPattern, DWORD dwFlags)
665 {
666     SecManagerImpl *This = impl_from_IInternetSecurityManager(iface);
667     HRESULT hres;
668
669     TRACE("(%p)->(%08x %s %08x)\n", iface, dwZone, debugstr_w(pwszPattern),dwFlags);
670
671     if(This->custom_manager) {
672         hres = IInternetSecurityManager_SetZoneMapping(This->custom_manager, dwZone,
673                 pwszPattern, dwFlags);
674         if(hres != INET_E_DEFAULT_ACTION)
675             return hres;
676     }
677
678     FIXME("Default action is not implemented\n");
679     return E_NOTIMPL;
680 }
681
682 static HRESULT WINAPI SecManagerImpl_GetZoneMappings(IInternetSecurityManager *iface,
683         DWORD dwZone, IEnumString **ppenumString, DWORD dwFlags)
684 {
685     SecManagerImpl *This = impl_from_IInternetSecurityManager(iface);
686     HRESULT hres;
687
688     TRACE("(%p)->(%08x %p %08x)\n", iface, dwZone, ppenumString,dwFlags);
689
690     if(This->custom_manager) {
691         hres = IInternetSecurityManager_GetZoneMappings(This->custom_manager, dwZone,
692                 ppenumString, dwFlags);
693         if(hres != INET_E_DEFAULT_ACTION)
694             return hres;
695     }
696
697     FIXME("Default action is not implemented\n");
698     return E_NOTIMPL;
699 }
700
701 static const IInternetSecurityManagerVtbl VT_SecManagerImpl =
702 {
703     SecManagerImpl_QueryInterface,
704     SecManagerImpl_AddRef,
705     SecManagerImpl_Release,
706     SecManagerImpl_SetSecuritySite,
707     SecManagerImpl_GetSecuritySite,
708     SecManagerImpl_MapUrlToZone,
709     SecManagerImpl_GetSecurityId,
710     SecManagerImpl_ProcessUrlAction,
711     SecManagerImpl_QueryCustomPolicy,
712     SecManagerImpl_SetZoneMapping,
713     SecManagerImpl_GetZoneMappings
714 };
715
716 HRESULT SecManagerImpl_Construct(IUnknown *pUnkOuter, LPVOID *ppobj)
717 {
718     SecManagerImpl *This;
719
720     TRACE("(%p,%p)\n",pUnkOuter,ppobj);
721     This = heap_alloc(sizeof(*This));
722
723     /* Initialize the virtual function table. */
724     This->IInternetSecurityManager_iface.lpVtbl = &VT_SecManagerImpl;
725
726     This->ref = 1;
727     This->mgrsite = NULL;
728     This->custom_manager = NULL;
729
730     *ppobj = This;
731
732     URLMON_LockModule();
733
734     return S_OK;
735 }
736
737 /***********************************************************************
738  *           InternetZoneManager implementation
739  *
740  */
741 typedef struct {
742     IInternetZoneManagerEx2 IInternetZoneManagerEx2_iface;
743     LONG ref;
744     LPDWORD *zonemaps;
745     DWORD zonemap_count;
746 } ZoneMgrImpl;
747
748 static inline ZoneMgrImpl *impl_from_IInternetZoneManagerEx2(IInternetZoneManagerEx2 *iface)
749 {
750     return CONTAINING_RECORD(iface, ZoneMgrImpl, IInternetZoneManagerEx2_iface);
751 }
752
753
754 /***********************************************************************
755  * build_zonemap_from_reg [internal]
756  *
757  * Enumerate the Zones in the Registry and return the Zones in a DWORD-array
758  * The number of the Zones is returned in data[0]
759  */
760 static LPDWORD build_zonemap_from_reg(void)
761 {
762     WCHAR name[32];
763     HKEY hkey;
764     LPDWORD data = NULL;
765     DWORD allocated = 6; /* space for the zonecount and Zone "0" up to Zone "4" */
766     DWORD used = 0;
767     DWORD res;
768     DWORD len;
769
770
771     res = RegOpenKeyW(HKEY_CURRENT_USER, wszZonesKey, &hkey);
772     if (res)
773         return NULL;
774
775     data = heap_alloc(allocated * sizeof(DWORD));
776     if (!data)
777         goto cleanup;
778
779     while (!res) {
780         name[0] = '\0';
781         len = sizeof(name) / sizeof(name[0]);
782         res = RegEnumKeyExW(hkey, used, name, &len, NULL, NULL, NULL, NULL);
783
784         if (!res) {
785             used++;
786             if (used == allocated) {
787                 LPDWORD new_data;
788
789                 allocated *= 2;
790                 new_data = heap_realloc_zero(data, allocated * sizeof(DWORD));
791                 if (!new_data)
792                     goto cleanup;
793
794                 data = new_data;
795             }
796             data[used] = atoiW(name);
797         }
798     }
799     if (used) {
800         RegCloseKey(hkey);
801         data[0] = used;
802         return data;
803     }
804
805 cleanup:
806     /* something failed */
807     RegCloseKey(hkey);
808     heap_free(data);
809     return NULL;
810 }
811
812 /********************************************************************
813  *      IInternetZoneManager_QueryInterface
814  */
815 static HRESULT WINAPI ZoneMgrImpl_QueryInterface(IInternetZoneManagerEx2* iface, REFIID riid, void** ppvObject)
816 {
817     ZoneMgrImpl* This = impl_from_IInternetZoneManagerEx2(iface);
818
819     TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(riid), ppvObject);
820
821     if(!This || !ppvObject)
822         return E_INVALIDARG;
823
824     if(IsEqualIID(&IID_IUnknown, riid)) {
825         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppvObject);
826     }else if(IsEqualIID(&IID_IInternetZoneManager, riid)) {
827         TRACE("(%p)->(IID_InternetZoneManager %p)\n", This, ppvObject);
828     }else if(IsEqualIID(&IID_IInternetZoneManagerEx, riid)) {
829         TRACE("(%p)->(IID_InternetZoneManagerEx %p)\n", This, ppvObject);
830     }else if(IsEqualIID(&IID_IInternetZoneManagerEx2, riid)) {
831         TRACE("(%p)->(IID_InternetZoneManagerEx2 %p)\n", This, ppvObject);
832     }
833     else
834     {
835         FIXME("Unknown interface: %s\n", debugstr_guid(riid));
836         *ppvObject = NULL;
837         return E_NOINTERFACE;
838     }
839
840     *ppvObject = iface;
841     IInternetZoneManager_AddRef(iface);
842     return S_OK;
843 }
844
845 /********************************************************************
846  *      IInternetZoneManager_AddRef
847  */
848 static ULONG WINAPI ZoneMgrImpl_AddRef(IInternetZoneManagerEx2* iface)
849 {
850     ZoneMgrImpl* This = impl_from_IInternetZoneManagerEx2(iface);
851     ULONG refCount = InterlockedIncrement(&This->ref);
852
853     TRACE("(%p)->(ref before=%u)\n",This, refCount - 1);
854
855     return refCount;
856 }
857
858 /********************************************************************
859  *      IInternetZoneManager_Release
860  */
861 static ULONG WINAPI ZoneMgrImpl_Release(IInternetZoneManagerEx2* iface)
862 {
863     ZoneMgrImpl* This = impl_from_IInternetZoneManagerEx2(iface);
864     ULONG refCount = InterlockedDecrement(&This->ref);
865
866     TRACE("(%p)->(ref before=%u)\n",This, refCount + 1);
867
868     if(!refCount) {
869         while (This->zonemap_count) heap_free(This->zonemaps[--This->zonemap_count]);
870         heap_free(This->zonemaps);
871         heap_free(This);
872         URLMON_UnlockModule();
873     }
874     
875     return refCount;
876 }
877
878 /********************************************************************
879  *      IInternetZoneManager_GetZoneAttributes
880  */
881 static HRESULT WINAPI ZoneMgrImpl_GetZoneAttributes(IInternetZoneManagerEx2* iface,
882                                                     DWORD dwZone,
883                                                     ZONEATTRIBUTES* pZoneAttributes)
884 {
885     ZoneMgrImpl* This = impl_from_IInternetZoneManagerEx2(iface);
886     HRESULT hr;
887     HKEY hcu;
888     HKEY hklm = NULL;
889
890     TRACE("(%p)->(%d %p)\n", This, dwZone, pZoneAttributes);
891
892     if (!pZoneAttributes)
893         return E_INVALIDARG;
894
895     hr = open_zone_key(HKEY_CURRENT_USER, dwZone, &hcu);
896     if (FAILED(hr))
897         return S_OK;  /* IE6 and older returned E_FAIL here */
898
899     hr = open_zone_key(HKEY_LOCAL_MACHINE, dwZone, &hklm);
900     if (FAILED(hr))
901         TRACE("Zone %d not in HKLM\n", dwZone);
902
903     get_string_from_reg(hcu, hklm, displaynameW, pZoneAttributes->szDisplayName, MAX_ZONE_PATH);
904     get_string_from_reg(hcu, hklm, descriptionW, pZoneAttributes->szDescription, MAX_ZONE_DESCRIPTION);
905     get_string_from_reg(hcu, hklm, iconW, pZoneAttributes->szIconPath, MAX_ZONE_PATH);
906     get_dword_from_reg(hcu, hklm, minlevelW, &pZoneAttributes->dwTemplateMinLevel);
907     get_dword_from_reg(hcu, hklm, currentlevelW, &pZoneAttributes->dwTemplateCurrentLevel);
908     get_dword_from_reg(hcu, hklm, recommendedlevelW, &pZoneAttributes->dwTemplateRecommended);
909     get_dword_from_reg(hcu, hklm, flagsW, &pZoneAttributes->dwFlags);
910
911     RegCloseKey(hklm);
912     RegCloseKey(hcu);
913     return S_OK;
914 }
915
916 /********************************************************************
917  *      IInternetZoneManager_SetZoneAttributes
918  */
919 static HRESULT WINAPI ZoneMgrImpl_SetZoneAttributes(IInternetZoneManagerEx2* iface,
920                                                     DWORD dwZone,
921                                                     ZONEATTRIBUTES* pZoneAttributes)
922 {
923     FIXME("(%p)->(%08x %p) stub\n", iface, dwZone, pZoneAttributes);
924     return E_NOTIMPL;
925 }
926
927 /********************************************************************
928  *      IInternetZoneManager_GetZoneCustomPolicy
929  */
930 static HRESULT WINAPI ZoneMgrImpl_GetZoneCustomPolicy(IInternetZoneManagerEx2* iface,
931                                                       DWORD dwZone,
932                                                       REFGUID guidKey,
933                                                       BYTE** ppPolicy,
934                                                       DWORD* pcbPolicy,
935                                                       URLZONEREG ulrZoneReg)
936 {
937     FIXME("(%p)->(%08x %s %p %p %08x) stub\n", iface, dwZone, debugstr_guid(guidKey),
938                                                     ppPolicy, pcbPolicy, ulrZoneReg);
939     return E_NOTIMPL;
940 }
941
942 /********************************************************************
943  *      IInternetZoneManager_SetZoneCustomPolicy
944  */
945 static HRESULT WINAPI ZoneMgrImpl_SetZoneCustomPolicy(IInternetZoneManagerEx2* iface,
946                                                       DWORD dwZone,
947                                                       REFGUID guidKey,
948                                                       BYTE* ppPolicy,
949                                                       DWORD cbPolicy,
950                                                       URLZONEREG ulrZoneReg)
951 {
952     FIXME("(%p)->(%08x %s %p %08x %08x) stub\n", iface, dwZone, debugstr_guid(guidKey),
953                                                     ppPolicy, cbPolicy, ulrZoneReg);
954     return E_NOTIMPL;
955 }
956
957 /********************************************************************
958  *      IInternetZoneManager_GetZoneActionPolicy
959  */
960 static HRESULT WINAPI ZoneMgrImpl_GetZoneActionPolicy(IInternetZoneManagerEx2* iface,
961         DWORD dwZone, DWORD dwAction, BYTE* pPolicy, DWORD cbPolicy, URLZONEREG urlZoneReg)
962 {
963     TRACE("(%p)->(%d %08x %p %d %d)\n", iface, dwZone, dwAction, pPolicy,
964             cbPolicy, urlZoneReg);
965
966     if(!pPolicy)
967         return E_INVALIDARG;
968
969     return get_action_policy(dwZone, dwAction, pPolicy, cbPolicy, urlZoneReg);
970 }
971
972 /********************************************************************
973  *      IInternetZoneManager_SetZoneActionPolicy
974  */
975 static HRESULT WINAPI ZoneMgrImpl_SetZoneActionPolicy(IInternetZoneManagerEx2* iface,
976                                                       DWORD dwZone,
977                                                       DWORD dwAction,
978                                                       BYTE* pPolicy,
979                                                       DWORD cbPolicy,
980                                                       URLZONEREG urlZoneReg)
981 {
982     FIXME("(%p)->(%08x %08x %p %08x %08x) stub\n", iface, dwZone, dwAction, pPolicy,
983                                                        cbPolicy, urlZoneReg);
984     return E_NOTIMPL;
985 }
986
987 /********************************************************************
988  *      IInternetZoneManager_PromptAction
989  */
990 static HRESULT WINAPI ZoneMgrImpl_PromptAction(IInternetZoneManagerEx2* iface,
991                                                DWORD dwAction,
992                                                HWND hwndParent,
993                                                LPCWSTR pwszUrl,
994                                                LPCWSTR pwszText,
995                                                DWORD dwPromptFlags)
996 {
997     FIXME("%p %08x %p %s %s %08x\n", iface, dwAction, hwndParent,
998           debugstr_w(pwszUrl), debugstr_w(pwszText), dwPromptFlags );
999     return E_NOTIMPL;
1000 }
1001
1002 /********************************************************************
1003  *      IInternetZoneManager_LogAction
1004  */
1005 static HRESULT WINAPI ZoneMgrImpl_LogAction(IInternetZoneManagerEx2* iface,
1006                                             DWORD dwAction,
1007                                             LPCWSTR pwszUrl,
1008                                             LPCWSTR pwszText,
1009                                             DWORD dwLogFlags)
1010 {
1011     FIXME("(%p)->(%08x %s %s %08x) stub\n", iface, dwAction, debugstr_w(pwszUrl),
1012                                               debugstr_w(pwszText), dwLogFlags);
1013     return E_NOTIMPL;
1014 }
1015
1016 /********************************************************************
1017  *      IInternetZoneManager_CreateZoneEnumerator
1018  */
1019 static HRESULT WINAPI ZoneMgrImpl_CreateZoneEnumerator(IInternetZoneManagerEx2* iface,
1020                                                        DWORD* pdwEnum,
1021                                                        DWORD* pdwCount,
1022                                                        DWORD dwFlags)
1023 {
1024     ZoneMgrImpl* This = impl_from_IInternetZoneManagerEx2(iface);
1025     LPDWORD * new_maps;
1026     LPDWORD data;
1027     DWORD i;
1028
1029     TRACE("(%p)->(%p, %p, 0x%08x)\n", This, pdwEnum, pdwCount, dwFlags);
1030     if (!pdwEnum || !pdwCount || (dwFlags != 0))
1031         return E_INVALIDARG;
1032
1033     data = build_zonemap_from_reg();
1034     TRACE("found %d zones\n", data ? data[0] : -1);
1035
1036     if (!data)
1037         return E_FAIL;
1038
1039     for (i = 0; i < This->zonemap_count; i++) {
1040         if (This->zonemaps && !This->zonemaps[i]) {
1041             This->zonemaps[i] = data;
1042             *pdwEnum = i;
1043             *pdwCount = data[0];
1044             return S_OK;
1045         }
1046     }
1047
1048     if (This->zonemaps) {
1049         /* try to double the nr. of pointers in the array */
1050         new_maps = heap_realloc_zero(This->zonemaps, This->zonemap_count * 2 * sizeof(LPDWORD));
1051         if (new_maps)
1052             This->zonemap_count *= 2;
1053     }
1054     else
1055     {
1056         This->zonemap_count = 2;
1057         new_maps = heap_alloc_zero(This->zonemap_count * sizeof(LPDWORD));
1058     }
1059
1060     if (!new_maps) {
1061         heap_free(data);
1062         return E_FAIL;
1063     }
1064     This->zonemaps = new_maps;
1065     This->zonemaps[i] = data;
1066     *pdwEnum = i;
1067     *pdwCount = data[0];
1068     return S_OK;
1069 }
1070
1071 /********************************************************************
1072  *      IInternetZoneManager_GetZoneAt
1073  */
1074 static HRESULT WINAPI ZoneMgrImpl_GetZoneAt(IInternetZoneManagerEx2* iface,
1075                                             DWORD dwEnum,
1076                                             DWORD dwIndex,
1077                                             DWORD* pdwZone)
1078 {
1079     ZoneMgrImpl* This = impl_from_IInternetZoneManagerEx2(iface);
1080     LPDWORD data;
1081
1082     TRACE("(%p)->(0x%08x, %d, %p)\n", This, dwEnum, dwIndex, pdwZone);
1083
1084     /* make sure, that dwEnum and dwIndex are in the valid range */
1085     if (dwEnum < This->zonemap_count) {
1086         if ((data = This->zonemaps[dwEnum])) {
1087             if (dwIndex < data[0]) {
1088                 *pdwZone = data[dwIndex + 1];
1089                 return S_OK;
1090             }
1091         }
1092     }
1093     return E_INVALIDARG;
1094 }
1095
1096 /********************************************************************
1097  *      IInternetZoneManager_DestroyZoneEnumerator
1098  */
1099 static HRESULT WINAPI ZoneMgrImpl_DestroyZoneEnumerator(IInternetZoneManagerEx2* iface,
1100                                                         DWORD dwEnum)
1101 {
1102     ZoneMgrImpl* This = impl_from_IInternetZoneManagerEx2(iface);
1103     LPDWORD data;
1104
1105     TRACE("(%p)->(0x%08x)\n", This, dwEnum);
1106     /* make sure, that dwEnum is valid */
1107     if (dwEnum < This->zonemap_count) {
1108         if ((data = This->zonemaps[dwEnum])) {
1109             This->zonemaps[dwEnum] = NULL;
1110             heap_free(data);
1111             return S_OK;
1112         }
1113     }
1114     return E_INVALIDARG;
1115 }
1116
1117 /********************************************************************
1118  *      IInternetZoneManager_CopyTemplatePoliciesToZone
1119  */
1120 static HRESULT WINAPI ZoneMgrImpl_CopyTemplatePoliciesToZone(IInternetZoneManagerEx2* iface,
1121                                                              DWORD dwTemplate,
1122                                                              DWORD dwZone,
1123                                                              DWORD dwReserved)
1124 {
1125     FIXME("(%p)->(%08x %08x %08x) stub\n", iface, dwTemplate, dwZone, dwReserved);
1126     return E_NOTIMPL;
1127 }
1128
1129 /********************************************************************
1130  *      IInternetZoneManagerEx_GetZoneActionPolicyEx
1131  */
1132 static HRESULT WINAPI ZoneMgrImpl_GetZoneActionPolicyEx(IInternetZoneManagerEx2* iface,
1133                                                         DWORD dwZone,
1134                                                         DWORD dwAction,
1135                                                         BYTE* pPolicy,
1136                                                         DWORD cbPolicy,
1137                                                         URLZONEREG urlZoneReg,
1138                                                         DWORD dwFlags)
1139 {
1140     TRACE("(%p)->(%d, 0x%x, %p, %d, %d, 0x%x)\n", iface, dwZone,
1141             dwAction, pPolicy, cbPolicy, urlZoneReg, dwFlags);
1142
1143     if(!pPolicy)
1144         return E_INVALIDARG;
1145
1146     if (dwFlags)
1147         FIXME("dwFlags 0x%x ignored\n", dwFlags);
1148
1149     return get_action_policy(dwZone, dwAction, pPolicy, cbPolicy, urlZoneReg);
1150 }
1151
1152 /********************************************************************
1153  *      IInternetZoneManagerEx_SetZoneActionPolicyEx
1154  */
1155 static HRESULT WINAPI ZoneMgrImpl_SetZoneActionPolicyEx(IInternetZoneManagerEx2* iface,
1156                                                         DWORD dwZone,
1157                                                         DWORD dwAction,
1158                                                         BYTE* pPolicy,
1159                                                         DWORD cbPolicy,
1160                                                         URLZONEREG urlZoneReg,
1161                                                         DWORD dwFlags)
1162 {
1163     FIXME("(%p)->(%d, 0x%x, %p, %d, %d, 0x%x) stub\n", iface, dwZone, dwAction, pPolicy,
1164                                                        cbPolicy, urlZoneReg, dwFlags);
1165     return E_NOTIMPL;
1166 }
1167
1168 /********************************************************************
1169  *      IInternetZoneManagerEx2_GetZoneAttributesEx
1170  */
1171 static HRESULT WINAPI ZoneMgrImpl_GetZoneAttributesEx(IInternetZoneManagerEx2* iface,
1172                                                       DWORD dwZone,
1173                                                       ZONEATTRIBUTES* pZoneAttributes,
1174                                                       DWORD dwFlags)
1175 {
1176     TRACE("(%p)->(%d, %p, 0x%x)\n", iface, dwZone, pZoneAttributes, dwFlags);
1177
1178     if (dwFlags)
1179         FIXME("dwFlags 0x%x ignored\n", dwFlags);
1180
1181     return IInternetZoneManager_GetZoneAttributes(iface, dwZone, pZoneAttributes);
1182 }
1183
1184
1185 /********************************************************************
1186  *      IInternetZoneManagerEx2_GetZoneSecurityState
1187  */
1188 static HRESULT WINAPI ZoneMgrImpl_GetZoneSecurityState(IInternetZoneManagerEx2* iface,
1189                                                        DWORD dwZoneIndex,
1190                                                        BOOL fRespectPolicy,
1191                                                        LPDWORD pdwState,
1192                                                        BOOL *pfPolicyEncountered)
1193 {
1194     FIXME("(%p)->(%d, %d, %p, %p) stub\n", iface, dwZoneIndex, fRespectPolicy,
1195                                            pdwState, pfPolicyEncountered);
1196
1197     *pdwState = SECURITY_IE_STATE_GREEN;
1198
1199     if (pfPolicyEncountered)
1200         *pfPolicyEncountered = FALSE;
1201
1202     return S_OK;
1203 }
1204
1205 /********************************************************************
1206  *      IInternetZoneManagerEx2_GetIESecurityState
1207  */
1208 static HRESULT WINAPI ZoneMgrImpl_GetIESecurityState(IInternetZoneManagerEx2* iface,
1209                                                      BOOL fRespectPolicy,
1210                                                      LPDWORD pdwState,
1211                                                      BOOL *pfPolicyEncountered,
1212                                                      BOOL fNoCache)
1213 {
1214     FIXME("(%p)->(%d, %p, %p, %d) stub\n", iface, fRespectPolicy, pdwState,
1215                                            pfPolicyEncountered, fNoCache);
1216
1217     *pdwState = SECURITY_IE_STATE_GREEN;
1218
1219     if (pfPolicyEncountered)
1220         *pfPolicyEncountered = FALSE;
1221
1222     return S_OK;
1223 }
1224
1225 /********************************************************************
1226  *      IInternetZoneManagerEx2_FixInsecureSettings
1227  */
1228 static HRESULT WINAPI ZoneMgrImpl_FixInsecureSettings(IInternetZoneManagerEx2* iface)
1229 {
1230     FIXME("(%p) stub\n", iface);
1231     return S_OK;
1232 }
1233
1234 /********************************************************************
1235  *      IInternetZoneManager_Construct
1236  */
1237 static const IInternetZoneManagerEx2Vtbl ZoneMgrImplVtbl = {
1238     ZoneMgrImpl_QueryInterface,
1239     ZoneMgrImpl_AddRef,
1240     ZoneMgrImpl_Release,
1241     /* IInternetZoneManager */
1242     ZoneMgrImpl_GetZoneAttributes,
1243     ZoneMgrImpl_SetZoneAttributes,
1244     ZoneMgrImpl_GetZoneCustomPolicy,
1245     ZoneMgrImpl_SetZoneCustomPolicy,
1246     ZoneMgrImpl_GetZoneActionPolicy,
1247     ZoneMgrImpl_SetZoneActionPolicy,
1248     ZoneMgrImpl_PromptAction,
1249     ZoneMgrImpl_LogAction,
1250     ZoneMgrImpl_CreateZoneEnumerator,
1251     ZoneMgrImpl_GetZoneAt,
1252     ZoneMgrImpl_DestroyZoneEnumerator,
1253     ZoneMgrImpl_CopyTemplatePoliciesToZone,
1254     /* IInternetZoneManagerEx */
1255     ZoneMgrImpl_GetZoneActionPolicyEx,
1256     ZoneMgrImpl_SetZoneActionPolicyEx,
1257     /* IInternetZoneManagerEx2 */
1258     ZoneMgrImpl_GetZoneAttributesEx,
1259     ZoneMgrImpl_GetZoneSecurityState,
1260     ZoneMgrImpl_GetIESecurityState,
1261     ZoneMgrImpl_FixInsecureSettings,
1262 };
1263
1264 HRESULT ZoneMgrImpl_Construct(IUnknown *pUnkOuter, LPVOID *ppobj)
1265 {
1266     ZoneMgrImpl* ret = heap_alloc_zero(sizeof(ZoneMgrImpl));
1267
1268     TRACE("(%p %p)\n", pUnkOuter, ppobj);
1269     ret->IInternetZoneManagerEx2_iface.lpVtbl = &ZoneMgrImplVtbl;
1270     ret->ref = 1;
1271     *ppobj = (IInternetZoneManagerEx*)ret;
1272
1273     URLMON_LockModule();
1274
1275     return S_OK;
1276 }
1277
1278 /***********************************************************************
1279  *           CoInternetCreateSecurityManager (URLMON.@)
1280  *
1281  */
1282 HRESULT WINAPI CoInternetCreateSecurityManager( IServiceProvider *pSP,
1283     IInternetSecurityManager **ppSM, DWORD dwReserved )
1284 {
1285     TRACE("%p %p %d\n", pSP, ppSM, dwReserved );
1286
1287     if(pSP)
1288         FIXME("pSP not supported\n");
1289
1290     return SecManagerImpl_Construct(NULL, (void**) ppSM);
1291 }
1292
1293 /********************************************************************
1294  *      CoInternetCreateZoneManager (URLMON.@)
1295  */
1296 HRESULT WINAPI CoInternetCreateZoneManager(IServiceProvider* pSP, IInternetZoneManager** ppZM, DWORD dwReserved)
1297 {
1298     TRACE("(%p %p %x)\n", pSP, ppZM, dwReserved);
1299     return ZoneMgrImpl_Construct(NULL, (void**)ppZM);
1300 }
1301
1302 /********************************************************************
1303  *      CoInternetGetSecurityUrl (URLMON.@)
1304  */
1305 HRESULT WINAPI CoInternetGetSecurityUrl(LPCWSTR pwzUrl, LPWSTR *ppwzSecUrl, PSUACTION psuAction, DWORD dwReserved)
1306 {
1307     WCHAR buf1[INTERNET_MAX_URL_LENGTH], buf2[INTERNET_MAX_URL_LENGTH];
1308     LPWSTR url, domain;
1309     DWORD len;
1310     HRESULT hres;
1311
1312     TRACE("(%p,%p,%u,%u)\n", pwzUrl, ppwzSecUrl, psuAction, dwReserved);
1313
1314     url = buf1;
1315     domain = buf2;
1316     strcpyW(url, pwzUrl);
1317
1318     while(1) {
1319         hres = CoInternetParseUrl(url, PARSE_SECURITY_URL, 0, domain, INTERNET_MAX_URL_LENGTH, &len, 0);
1320         if(hres!=S_OK || !strcmpW(url, domain))
1321             break;
1322
1323         if(url == buf1) {
1324             url = buf2;
1325             domain = buf1;
1326         } else {
1327             url = buf1;
1328             domain = buf2;
1329         }
1330     }
1331
1332     if(psuAction==PSU_SECURITY_URL_ONLY) {
1333         len = lstrlenW(url)+1;
1334         *ppwzSecUrl = CoTaskMemAlloc(len*sizeof(WCHAR));
1335         if(!*ppwzSecUrl)
1336             return E_OUTOFMEMORY;
1337
1338         memcpy(*ppwzSecUrl, url, len*sizeof(WCHAR));
1339         return S_OK;
1340     }
1341
1342     hres = CoInternetParseUrl(url, PARSE_SECURITY_DOMAIN, 0, domain,
1343             INTERNET_MAX_URL_LENGTH, &len, 0);
1344     if(SUCCEEDED(hres)) {
1345         len++;
1346         *ppwzSecUrl = CoTaskMemAlloc(len*sizeof(WCHAR));
1347         if(!*ppwzSecUrl)
1348             return E_OUTOFMEMORY;
1349
1350         memcpy(*ppwzSecUrl, domain, len*sizeof(WCHAR));
1351         return S_OK;
1352     }
1353
1354     hres = CoInternetParseUrl(url, PARSE_SCHEMA, 0, domain,
1355             INTERNET_MAX_URL_LENGTH, &len, 0);
1356     if(hres == S_OK){
1357         const WCHAR fileW[] = {'f','i','l','e',0};
1358         if(!strcmpW(domain, fileW)){
1359             hres = CoInternetParseUrl(url, PARSE_ROOTDOCUMENT, 0, domain, INTERNET_MAX_URL_LENGTH, &len, 0);
1360         }else{
1361             domain[len] = ':';
1362             hres = CoInternetParseUrl(url, PARSE_DOMAIN, 0, domain+len+1,
1363                     INTERNET_MAX_URL_LENGTH-len-1, &len, 0);
1364             if(hres == S_OK) {
1365                 len = lstrlenW(domain)+1;
1366                 *ppwzSecUrl = CoTaskMemAlloc(len*sizeof(WCHAR));
1367                 if(!*ppwzSecUrl)
1368                     return E_OUTOFMEMORY;
1369
1370                 memcpy(*ppwzSecUrl, domain, len*sizeof(WCHAR));
1371                 return S_OK;
1372             }
1373         }
1374     }else
1375         return hres;
1376
1377     len = lstrlenW(url)+1;
1378     *ppwzSecUrl = CoTaskMemAlloc(len*sizeof(WCHAR));
1379     if(!*ppwzSecUrl)
1380         return E_OUTOFMEMORY;
1381
1382     memcpy(*ppwzSecUrl, url, len*sizeof(WCHAR));
1383     return S_OK;
1384 }
1385
1386 /********************************************************************
1387  *      CoInternetGetSecurityUrlEx (URLMON.@)
1388  */
1389 HRESULT WINAPI CoInternetGetSecurityUrlEx(IUri *pUri, IUri **ppSecUri, PSUACTION psuAction, DWORD_PTR dwReserved)
1390 {
1391     HRESULT hres;
1392     BSTR secure_uri;
1393     URL_SCHEME scheme_type;
1394
1395     TRACE("(%p,%p,%u,%u)\n", pUri, ppSecUri, psuAction, (DWORD)dwReserved);
1396
1397     if(!pUri || !ppSecUri)
1398         return E_INVALIDARG;
1399
1400     /* Try to find the Security url using pluggable protocols first. */
1401     hres = parse_security_uri(pUri, psuAction, ppSecUri);
1402     if(FAILED(hres) || *ppSecUri)
1403         return hres;
1404
1405     hres = IUri_GetScheme(pUri, (DWORD*)&scheme_type);
1406     if(FAILED(hres))
1407         return hres;
1408
1409     hres = IUri_GetDisplayUri(pUri, &secure_uri);
1410     if(FAILED(hres))
1411         return hres;
1412
1413     /* File URIs have to hierarchical. */
1414     if(scheme_type == URL_SCHEME_FILE) {
1415         const WCHAR *tmp = secure_uri;
1416
1417         /* Check and see if a "//" is after the scheme name. */
1418         tmp += sizeof(fileW)/sizeof(WCHAR);
1419         if(*tmp != '/' || *(tmp+1) != '/') {
1420             SysFreeString(secure_uri);
1421             return E_INVALIDARG;
1422         }
1423     }
1424
1425     hres = CreateUri(secure_uri, Uri_CREATE_ALLOW_IMPLICIT_WILDCARD_SCHEME, 0, ppSecUri);
1426     SysFreeString(secure_uri);
1427
1428     return hres;
1429 }