sec_mgr.c 68.2 KB
Newer Older
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 10 11 12 13 14 15 16 17 18 19 20
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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 25
 */

#include <stdio.h>

Jacek Caban's avatar
Jacek Caban committed
26
#include "urlmon_main.h"
27
#include "winreg.h"
28
#include "wininet.h"
Jacek Caban's avatar
Jacek Caban committed
29

30 31 32
#define NO_SHLWAPI_REG
#include "shlwapi.h"

33 34 35 36
#include "wine/debug.h"

WINE_DEFAULT_DEBUG_CHANNEL(urlmon);

37 38 39
static const WCHAR currentlevelW[] = {'C','u','r','r','e','n','t','L','e','v','e','l',0};
static const WCHAR descriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
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 42 43 44 45
static const WCHAR flagsW[] = {'F','l','a','g','s',0};
static const WCHAR iconW[] = {'I','c','o','n',0};
static const WCHAR minlevelW[] = {'M','i','n','L','e','v','e','l',0};
static const WCHAR recommendedlevelW[] = {'R','e','c','o','m','m','e','n','d','e','d',
                                          'L','e','v','e','l',0};
46 47 48 49 50 51
static const WCHAR wszZonesKey[] = {'S','o','f','t','w','a','r','e','\\',
                                    'M','i','c','r','o','s','o','f','t','\\',
                                    'W','i','n','d','o','w','s','\\',
                                    'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
                                    'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s','\\',
                                    'Z','o','n','e','s','\\',0};
52 53 54 55 56 57 58
static const WCHAR wszZoneMapDomainsKey[] = {'S','o','f','t','w','a','r','e','\\',
                                             'M','i','c','r','o','s','o','f','t','\\',
                                             'W','i','n','d','o','w','s','\\',
                                             'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
                                             'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s','\\',
                                             'Z','o','n','e','M','a','p','\\',
                                             'D','o','m','a','i','n','s',0};
59

60 61 62 63 64
static inline BOOL is_drive_path(const WCHAR *path)
{
    return isalphaW(*path) && *(path+1) == ':';
}

65 66 67 68 69 70 71 72 73
/* List of schemes types Windows seems to expect to be hierarchical. */
static inline BOOL is_hierarchical_scheme(URL_SCHEME type) {
    return(type == URL_SCHEME_HTTP || type == URL_SCHEME_FTP ||
           type == URL_SCHEME_GOPHER || type == URL_SCHEME_NNTP ||
           type == URL_SCHEME_TELNET || type == URL_SCHEME_WAIS ||
           type == URL_SCHEME_FILE || type == URL_SCHEME_HTTPS ||
           type == URL_SCHEME_RES);
}

74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
/********************************************************************
 * get_string_from_reg [internal]
 *
 * helper to get a string from the reg.
 *
 */
static void get_string_from_reg(HKEY hcu, HKEY hklm, LPCWSTR name, LPWSTR out, DWORD maxlen)
{
    DWORD type = REG_SZ;
    DWORD len = maxlen * sizeof(WCHAR);
    DWORD res;

    res = RegQueryValueExW(hcu, name, NULL, &type, (LPBYTE) out, &len);

    if (res && hklm) {
        len = maxlen * sizeof(WCHAR);
        type = REG_SZ;
        res = RegQueryValueExW(hklm, name, NULL, &type, (LPBYTE) out, &len);
    }

    if (res) {
        TRACE("%s failed: %d\n", debugstr_w(name), res);
        *out = '\0';
    }
}

/********************************************************************
 * get_dword_from_reg [internal]
 *
 * helper to get a dword from the reg.
 *
 */
static void get_dword_from_reg(HKEY hcu, HKEY hklm, LPCWSTR name, LPDWORD out)
{
    DWORD type = REG_DWORD;
    DWORD len = sizeof(DWORD);
    DWORD res;

    res = RegQueryValueExW(hcu, name, NULL, &type, (LPBYTE) out, &len);

    if (res && hklm) {
        len = sizeof(DWORD);
        type = REG_DWORD;
        res = RegQueryValueExW(hklm, name, NULL, &type, (LPBYTE) out, &len);
    }

    if (res) {
        TRACE("%s failed: %d\n", debugstr_w(name), res);
        *out = 0;
    }
}
125

126
static HRESULT get_zone_from_reg(LPCWSTR schema, DWORD *zone)
127
{
128
    DWORD res, size;
129 130 131 132
    HKEY hkey;

    static const WCHAR wszZoneMapProtocolKey[] =
        {'S','o','f','t','w','a','r','e','\\',
133 134 135 136 137 138
         'M','i','c','r','o','s','o','f','t','\\',
         'W','i','n','d','o','w','s','\\',
         'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
         'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s','\\',
         'Z','o','n','e','M','a','p','\\',
         'P','r','o','t','o','c','o','l','D','e','f','a','u','l','t','s',0};
139 140 141 142 143 144 145 146 147

    res = RegOpenKeyW(HKEY_CURRENT_USER, wszZoneMapProtocolKey, &hkey);
    if(res != ERROR_SUCCESS) {
        ERR("Could not open key %s\n", debugstr_w(wszZoneMapProtocolKey));
        return E_UNEXPECTED;
    }

    size = sizeof(DWORD);
    res = RegQueryValueExW(hkey, schema, NULL, NULL, (PBYTE)zone, &size);
Jacek Caban's avatar
Jacek Caban committed
148
    RegCloseKey(hkey);
149 150 151 152 153 154 155 156 157 158 159
    if(res == ERROR_SUCCESS)
        return S_OK;

    res = RegOpenKeyW(HKEY_LOCAL_MACHINE, wszZoneMapProtocolKey, &hkey);
    if(res != ERROR_SUCCESS) {
        ERR("Could not open key %s\n", debugstr_w(wszZoneMapProtocolKey));
        return E_UNEXPECTED;
    }

    size = sizeof(DWORD);
    res = RegQueryValueExW(hkey, schema, NULL, NULL, (PBYTE)zone, &size);
Jacek Caban's avatar
Jacek Caban committed
160
    RegCloseKey(hkey);
161
    if(res == ERROR_SUCCESS)
162
        return S_OK;
163 164 165 166 167

    *zone = 3;
    return S_OK;
}

168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272
/********************************************************************
 * matches_domain_pattern [internal]
 *
 * Checks if the given string matches the specified domain pattern.
 *
 * This function looks for explicit wildcard domain components iff
 * they appear at the very beginning of the 'pattern' string
 *
 *  pattern = "*.google.com"
 */
static BOOL matches_domain_pattern(LPCWSTR pattern, LPCWSTR str, BOOL implicit_wildcard, LPCWSTR *matched)
{
    BOOL matches = FALSE;
    DWORD pattern_len = strlenW(pattern);
    DWORD str_len = strlenW(str);

    TRACE("(%d) Checking if %s matches %s\n", implicit_wildcard, debugstr_w(str), debugstr_w(pattern));

    *matched = NULL;
    if(str_len >= pattern_len) {
        /* Check if there's an explicit wildcard in the pattern. */
        if(pattern[0] == '*' && pattern[1] == '.') {
            /* Make sure that 'str' matches the wildcard pattern.
             *
             * Example:
             *  pattern = "*.google.com"
             *
             * So in this case 'str' would have to end with ".google.com" in order
             * to map to this pattern.
             */
            if(str_len >= pattern_len+1 && !strcmpiW(str+(str_len-pattern_len+1), pattern+1)) {
                /* Check if there's another '.' inside of the "unmatched" portion
                 * of 'str'.
                 *
                 * Example:
                 *  pattern = "*.google.com"
                 *  str     = "test.testing.google.com"
                 *
                 * The currently matched portion is ".google.com" in 'str', we need
                 * see if there's a '.' inside of the unmatched portion ("test.testing"), because
                 * if there is and 'implicit_wildcard' isn't set, then this isn't
                 * a match.
                 */
                const WCHAR *ptr;
                if(str_len > pattern_len+1 && (ptr = memrchrW(str, '.', str_len-pattern_len-2))) {
                    if(implicit_wildcard) {
                        matches = TRUE;
                        *matched = ptr+1;
                    }
                } else {
                    matches = TRUE;
                    *matched = str;
                }
            }
        } else if(implicit_wildcard && str_len > pattern_len) {
            /* When the pattern has an implicit wildcard component, it means
             * that anything goes in 'str' as long as it ends with the pattern
             * and that the beginning of the match has a '.' before it.
             *
             * Example:
             *  pattern = "google.com"
             *  str     = "www.google.com"
             *
             * Implicitly matches the pattern, where as:
             *
             *  pattern = "google.com"
             *  str     = "wwwgoogle.com"
             *
             * Doesn't match the pattern.
             */
            if(str_len > pattern_len) {
                if(str[str_len-pattern_len-1] == '.' && !strcmpiW(str+(str_len-pattern_len), pattern)) {
                    matches = TRUE;
                    *matched = str+(str_len-pattern_len);
                }
            }
        } else {
            /* The pattern doesn't have an implicit wildcard, or an explicit wildcard,
             * so 'str' has to be an exact match to the 'pattern'.
             */
            if(!strcmpiW(str, pattern)) {
                matches = TRUE;
                *matched = str;
            }
        }
    }

    if(matches)
        TRACE("Found a match: matched=%s\n", debugstr_w(*matched));
    else
        TRACE("No match found\n");

    return matches;
}

static BOOL get_zone_for_scheme(HKEY key, LPCWSTR schema, DWORD *zone)
{
    static const WCHAR wildcardW[] = {'*',0};

    DWORD res;
    DWORD size = sizeof(DWORD);
    DWORD type;

    /* See if the key contains a value for the scheme first. */
    res = RegQueryValueExW(key, schema, NULL, &type, (BYTE*)zone, &size);
273 274 275
    if(res == ERROR_SUCCESS) {
        if(type == REG_DWORD)
            return TRUE;
276
        WARN("Unexpected value type %d for value %s, expected REG_DWORD\n", type, debugstr_w(schema));
277 278 279 280 281 282 283
    }

    /* Try to get the zone for the wildcard scheme. */
    size = sizeof(DWORD);
    res = RegQueryValueExW(key, wildcardW, NULL, &type, (BYTE*)zone, &size);
    if(res != ERROR_SUCCESS)
        return FALSE;
284

285 286 287
    if(type != REG_DWORD) {
        WARN("Unexpected value type %d for value %s, expected REG_DWORD\n", type, debugstr_w(wildcardW));
        return FALSE;
288 289
    }

290
    return TRUE;
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455
}

/********************************************************************
 * search_domain_for_zone [internal]
 *
 * Searches the specified 'domain' registry key to see if 'host' maps into it, or any
 * of it's subdomain registry keys.
 *
 * Returns S_OK if a match is found, S_FALSE if no matches were found, or an error code.
 */
static HRESULT search_domain_for_zone(HKEY domains, LPCWSTR domain, DWORD domain_len, LPCWSTR schema,
                                      LPCWSTR host, DWORD host_len, DWORD *zone)
{
    BOOL found = FALSE;
    HKEY domain_key;
    DWORD res;
    LPCWSTR matched;

    if(host_len >= domain_len && matches_domain_pattern(domain, host, TRUE, &matched)) {
        res = RegOpenKeyW(domains, domain, &domain_key);
        if(res != ERROR_SUCCESS) {
            ERR("Failed to open domain key %s: %d\n", debugstr_w(domain), res);
            return E_UNEXPECTED;
        }

        if(matched == host)
            found = get_zone_for_scheme(domain_key, schema, zone);
        else {
            INT domain_offset;
            DWORD subdomain_count, subdomain_len;
            BOOL check_domain = TRUE;

            find_domain_name(domain, domain_len, &domain_offset);

            res = RegQueryInfoKeyW(domain_key, NULL, NULL, NULL, &subdomain_count, &subdomain_len,
                                   NULL, NULL, NULL, NULL, NULL, NULL);
            if(res != ERROR_SUCCESS) {
                ERR("Unable to query info for key %s: %d\n", debugstr_w(domain), res);
                RegCloseKey(domain_key);
                return E_UNEXPECTED;
            }

            if(subdomain_count) {
                WCHAR *subdomain;
                WCHAR *component;
                DWORD i;

                subdomain = heap_alloc((subdomain_len+1)*sizeof(WCHAR));
                if(!subdomain) {
                    RegCloseKey(domain_key);
                    return E_OUTOFMEMORY;
                }

                component = heap_strndupW(host, matched-host-1);
                if(!component) {
                    heap_free(subdomain);
                    RegCloseKey(domain_key);
                    return E_OUTOFMEMORY;
                }

                for(i = 0; i < subdomain_count; ++i) {
                    DWORD len = subdomain_len+1;
                    const WCHAR *sub_matched;

                    res = RegEnumKeyExW(domain_key, i, subdomain, &len, NULL, NULL, NULL, NULL);
                    if(res != ERROR_SUCCESS) {
                        heap_free(component);
                        heap_free(subdomain);
                        RegCloseKey(domain_key);
                        return E_UNEXPECTED;
                    }

                    if(matches_domain_pattern(subdomain, component, FALSE, &sub_matched)) {
                        HKEY subdomain_key;

                        res = RegOpenKeyW(domain_key, subdomain, &subdomain_key);
                        if(res != ERROR_SUCCESS) {
                            ERR("Unable to open subdomain key %s of %s: %d\n", debugstr_w(subdomain),
                                debugstr_w(domain), res);
                            heap_free(component);
                            heap_free(subdomain);
                            RegCloseKey(domain_key);
                            return E_UNEXPECTED;
                        }

                        found = get_zone_for_scheme(subdomain_key, schema, zone);
                        check_domain = FALSE;
                        RegCloseKey(subdomain_key);
                        break;
                    }
                }
                heap_free(subdomain);
                heap_free(component);
            }

            /* There's a chance that 'host' implicitly mapped into 'domain', in
             * which case we check to see if 'domain' contains zone information.
             *
             * This can only happen if 'domain' is it's own domain name.
             *  Example:
             *      "google.com" (domain name = "google.com")
             *
             *  So if:
             *      host = "www.google.com"
             *
             *  Then host would map directly into the "google.com" domain key.
             *
             * If 'domain' has more than just it's domain name, or it does not
             * have a domain name, then we don't perform the check. The reason
             * for this is that these domains don't allow implicit mappings.
             *  Example:
             *      domain = "org" (has no domain name)
             *      host   = "www.org"
             *
             *  The mapping would only happen if the "org" key had an explicit subkey
             *  called "www".
             */
            if(check_domain && !domain_offset && !strchrW(host, matched-host-1))
                found = get_zone_for_scheme(domain_key, schema, zone);
        }
        RegCloseKey(domain_key);
    }

    return found ? S_OK : S_FALSE;
}

static HRESULT search_for_domain_mapping(HKEY domains, LPCWSTR schema, LPCWSTR host, DWORD host_len, DWORD *zone)
{
    WCHAR *domain;
    DWORD domain_count, domain_len, i;
    DWORD res;
    HRESULT hres = S_FALSE;

    res = RegQueryInfoKeyW(domains, NULL, NULL, NULL, &domain_count, &domain_len,
                           NULL, NULL, NULL, NULL, NULL, NULL);
    if(res != ERROR_SUCCESS) {
        WARN("Failed to retrieve information about key\n");
        return E_UNEXPECTED;
    }

    if(!domain_count)
        return S_FALSE;

    domain = heap_alloc((domain_len+1)*sizeof(WCHAR));
    if(!domain)
        return E_OUTOFMEMORY;

    for(i = 0; i < domain_count; ++i) {
        DWORD len = domain_len+1;

        res = RegEnumKeyExW(domains, i, domain, &len, NULL, NULL, NULL, NULL);
        if(res != ERROR_SUCCESS) {
            heap_free(domain);
            return E_UNEXPECTED;
        }

        hres = search_domain_for_zone(domains, domain, len, schema, host, host_len, zone);
        if(FAILED(hres) || hres == S_OK)
            break;
    }

    heap_free(domain);
    return hres;
}

456
static HRESULT get_zone_from_domains(IUri *uri, DWORD *zone)
457 458
{
    HRESULT hres;
459
    BSTR host, scheme;
460 461
    DWORD res;
    HKEY domains;
462
    DWORD scheme_type;
463

464 465 466
    hres = IUri_GetScheme(uri, &scheme_type);
    if(FAILED(hres))
        return hres;
467 468 469 470

    /* Windows doesn't play nice with unknown scheme types when it tries
     * to check if a host name maps into any domains.
     */
471 472 473 474 475 476 477
    if(scheme_type == URL_SCHEME_UNKNOWN)
        return S_FALSE;

    hres = IUri_GetHost(uri, &host);
    if(FAILED(hres))
        return hres;

478 479 480 481 482 483 484 485 486 487 488 489 490
    /* Known hierarchical scheme types must have a host. If they don't Windows
     * assigns URLZONE_INVALID to the zone.
     */
    if((scheme_type != URL_SCHEME_UNKNOWN && scheme_type != URL_SCHEME_FILE)
        && is_hierarchical_scheme(scheme_type) && !*host) {
        *zone = URLZONE_INVALID;

        SysFreeString(host);

        /* The MapUrlToZone functions return S_OK when this condition occurs. */
        return S_OK;
    }

491 492 493
    hres = IUri_GetSchemeName(uri, &scheme);
    if(FAILED(hres)) {
        SysFreeString(host);
494 495 496 497 498 499
        return hres;
    }

    /* First try CURRENT_USER. */
    res = RegOpenKeyW(HKEY_CURRENT_USER, wszZoneMapDomainsKey, &domains);
    if(res == ERROR_SUCCESS) {
500
        hres = search_for_domain_mapping(domains, scheme, host, SysStringLen(host), zone);
501 502 503 504 505 506 507 508
        RegCloseKey(domains);
    } else
        WARN("Failed to open HKCU's %s key\n", debugstr_w(wszZoneMapDomainsKey));

    /* If that doesn't work try LOCAL_MACHINE. */
    if(hres == S_FALSE) {
        res = RegOpenKeyW(HKEY_LOCAL_MACHINE, wszZoneMapDomainsKey, &domains);
        if(res == ERROR_SUCCESS) {
509
            hres = search_for_domain_mapping(domains, scheme, host, SysStringLen(host), zone);
510 511 512 513 514
            RegCloseKey(domains);
        } else
            WARN("Failed to open HKLM's %s key\n", debugstr_w(wszZoneMapDomainsKey));
    }

515 516
    SysFreeString(host);
    SysFreeString(scheme);
517 518 519
    return hres;
}

520
static HRESULT map_security_uri_to_zone(IUri *uri, DWORD *zone)
521 522
{
    HRESULT hres;
523
    BSTR scheme;
524

525
    *zone = URLZONE_INVALID;
526

527 528 529
    hres = IUri_GetSchemeName(uri, &scheme);
    if(FAILED(hres))
        return hres;
530

531 532 533
    if(!strcmpiW(scheme, fileW)) {
        BSTR path;
        WCHAR *ptr, *path_start, root[20];
534

535 536 537 538 539
        hres = IUri_GetPath(uri, &path);
        if(FAILED(hres)) {
            SysFreeString(scheme);
            return hres;
        }
540

541 542 543 544
        if(*path == '/' && is_drive_path(path+1))
            path_start = path+1;
        else
            path_start = path;
545

546
        if((ptr = strchrW(path_start, ':')) && ptr-path_start+1 < sizeof(root)/sizeof(WCHAR)) {
547 548
            UINT type;

549 550
            memcpy(root, path_start, (ptr-path_start+1)*sizeof(WCHAR));
            root[ptr-path_start+1] = 0;
551 552 553 554 555 556 557 558 559 560 561

            type = GetDriveTypeW(root);

            switch(type) {
            case DRIVE_UNKNOWN:
            case DRIVE_NO_ROOT_DIR:
                break;
            case DRIVE_REMOVABLE:
            case DRIVE_FIXED:
            case DRIVE_CDROM:
            case DRIVE_RAMDISK:
562
                *zone = URLZONE_LOCAL_MACHINE;
563 564 565
                hres = S_OK;
                break;
            case DRIVE_REMOTE:
566
                *zone = URLZONE_INTERNET;
567 568 569 570 571 572
                hres = S_OK;
                break;
            default:
                FIXME("unsupported drive type %d\n", type);
            }
        }
573
        SysFreeString(path);
574 575
    }

576
    if(*zone == URLZONE_INVALID) {
577
        hres = get_zone_from_domains(uri, zone);
578
        if(hres == S_FALSE)
579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604
            hres = get_zone_from_reg(scheme, zone);
    }

    SysFreeString(scheme);
    return hres;
}

static HRESULT map_url_to_zone(LPCWSTR url, DWORD *zone, LPWSTR *ret_url)
{
    IUri *secur_uri;
    LPWSTR secur_url;
    HRESULT hres;

    *zone = URLZONE_INVALID;

    hres = CoInternetGetSecurityUrl(url, &secur_url, PSU_SECURITY_URL_ONLY, 0);
    if(hres != S_OK) {
        DWORD size = strlenW(url)*sizeof(WCHAR);

        secur_url = CoTaskMemAlloc(size);
        if(!secur_url)
            return E_OUTOFMEMORY;

        memcpy(secur_url, url, size);
    }

605
    hres = CreateUri(secur_url, Uri_CREATE_ALLOW_IMPLICIT_FILE_SCHEME, 0, &secur_uri);
606 607 608
    if(FAILED(hres)) {
        CoTaskMemFree(secur_url);
        return hres;
609 610
    }

611 612 613
    hres = map_security_uri_to_zone(secur_uri, zone);
    IUri_Release(secur_uri);

614
    if(FAILED(hres) || !ret_url)
615
        CoTaskMemFree(secur_url);
616 617 618 619 620 621
    else
        *ret_url = secur_url;

    return hres;
}

622
static HRESULT map_uri_to_zone(IUri *uri, DWORD *zone, IUri **ret_uri)
623 624 625 626 627 628 629 630 631
{
    HRESULT hres;
    IUri *secur_uri;

    hres = CoInternetGetSecurityUrlEx(uri, &secur_uri, PSU_SECURITY_URL_ONLY, 0);
    if(FAILED(hres))
        return hres;

    hres = map_security_uri_to_zone(secur_uri, zone);
632 633 634 635
    if(FAILED(hres) || !ret_uri)
        IUri_Release(secur_uri);
    else
        *ret_uri = secur_uri;
636 637 638 639

    return hres;
}

640 641
static HRESULT open_zone_key(HKEY parent_key, DWORD zone, HKEY *hkey)
{
642
    static const WCHAR wszFormat[] = {'%','s','%','u',0};
643

644
    WCHAR key_name[sizeof(wszZonesKey)/sizeof(WCHAR)+12];
645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665
    DWORD res;

    wsprintfW(key_name, wszFormat, wszZonesKey, zone);

    res = RegOpenKeyW(parent_key, key_name, hkey);

    if(res != ERROR_SUCCESS) {
        WARN("RegOpenKey failed\n");
        return E_INVALIDARG;
    }

    return S_OK;
}

static HRESULT get_action_policy(DWORD zone, DWORD action, BYTE *policy, DWORD size, URLZONEREG zone_reg)
{
    HKEY parent_key;
    HKEY hkey;
    LONG res;
    HRESULT hres;

666 667
    switch(action) {
    case URLACTION_SCRIPT_OVERRIDE_SAFETY:
668
    case URLACTION_ACTIVEX_OVERRIDE_SCRIPT_SAFETY:
669 670 671 672
        *(DWORD*)policy = URLPOLICY_DISALLOW;
        return S_OK;
    }

673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713
    switch(zone_reg) {
    case URLZONEREG_DEFAULT:
    case URLZONEREG_HKCU:
        parent_key = HKEY_CURRENT_USER;
        break;
    case URLZONEREG_HKLM:
        parent_key = HKEY_LOCAL_MACHINE;
        break;
    default:
        WARN("Unknown URLZONEREG: %d\n", zone_reg);
        return E_FAIL;
    };

    hres = open_zone_key(parent_key, zone, &hkey);
    if(SUCCEEDED(hres)) {
        WCHAR action_str[16];
        DWORD len = size;

        static const WCHAR formatW[] = {'%','X',0};

        wsprintfW(action_str, formatW, action);

        res = RegQueryValueExW(hkey, action_str, NULL, NULL, policy, &len);
        if(res == ERROR_MORE_DATA) {
            hres = E_INVALIDARG;
        }else if(res == ERROR_FILE_NOT_FOUND) {
            hres = E_FAIL;
        }else if(res != ERROR_SUCCESS) {
            ERR("RegQueryValue failed: %d\n", res);
            hres = E_UNEXPECTED;
        }

        RegCloseKey(hkey);
    }

    if(FAILED(hres) && zone_reg == URLZONEREG_DEFAULT)
        return get_action_policy(zone, action, policy, size, URLZONEREG_HKLM);

    return hres;
}

714
static HRESULT generate_security_id(IUri *uri, BYTE *secid, DWORD *secid_len, DWORD zone)
715
{
716
    DWORD len;
717
    HRESULT hres;
718
    DWORD scheme_type;
719

720
    if(zone == URLZONE_INVALID)
721 722 723 724 725 726 727 728 729 730 731 732 733
        return E_INVALIDARG;

    hres = IUri_GetScheme(uri, &scheme_type);
    if(FAILED(hres))
        return hres;

    /* Windows handles opaque URLs differently then hierarchical ones. */
    if(!is_hierarchical_scheme(scheme_type) && scheme_type != URL_SCHEME_WILDCARD) {
        BSTR display_uri;

        hres = IUri_GetDisplayUri(uri, &display_uri);
        if(FAILED(hres))
            return hres;
734

735
        len = WideCharToMultiByte(CP_ACP, 0, display_uri, -1, NULL, 0, NULL, NULL)-1;
736

737 738 739 740
        if(len+sizeof(DWORD) > *secid_len) {
            SysFreeString(display_uri);
            return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
        }
741

742 743
        WideCharToMultiByte(CP_ACP, 0, display_uri, -1, (LPSTR)secid, len, NULL, NULL);
        SysFreeString(display_uri);
744

745 746 747 748 749
        *(DWORD*)(secid+len) = zone;
    } else {
        BSTR host, scheme;
        DWORD host_len, scheme_len;
        BYTE *ptr;
750

751 752 753
        hres = IUri_GetHost(uri, &host);
        if(FAILED(hres))
            return hres;
754

755 756 757 758
        /* The host can't be empty for Wildcard URIs. */
        if(scheme_type == URL_SCHEME_WILDCARD && !*host) {
            SysFreeString(host);
            return E_INVALIDARG;
759 760
        }

761 762 763 764 765
        hres = IUri_GetSchemeName(uri, &scheme);
        if(FAILED(hres)) {
            SysFreeString(host);
            return hres;
        }
766

767 768
        host_len = WideCharToMultiByte(CP_ACP, 0, host, -1, NULL, 0, NULL, NULL)-1;
        scheme_len = WideCharToMultiByte(CP_ACP, 0, scheme, -1, NULL, 0, NULL, NULL)-1;
769

770
        len = host_len+scheme_len+sizeof(BYTE);
771

772 773 774 775 776
        if(len+sizeof(DWORD) > *secid_len) {
            SysFreeString(host);
            SysFreeString(scheme);
            return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
        }
777

778 779
        WideCharToMultiByte(CP_ACP, 0, scheme, -1, (LPSTR)secid, len, NULL, NULL);
        SysFreeString(scheme);
780

781 782 783 784 785 786 787 788 789 790
        ptr = secid+scheme_len;
        *ptr++ = ':';

        WideCharToMultiByte(CP_ACP, 0, host, -1, (LPSTR)ptr, host_len, NULL, NULL);
        SysFreeString(host);

        ptr += host_len;

        *(DWORD*)ptr = zone;
    }
791 792 793 794 795 796

    *secid_len = len+sizeof(DWORD);

    return S_OK;
}

797 798 799 800 801 802 803 804 805 806 807
static HRESULT get_security_id_for_url(LPCWSTR url, BYTE *secid, DWORD *secid_len)
{
    HRESULT hres;
    DWORD zone = URLZONE_INVALID;
    LPWSTR secur_url = NULL;
    IUri *uri;

    hres = map_url_to_zone(url, &zone, &secur_url);
    if(FAILED(hres))
        return hres == 0x80041001 ? E_INVALIDARG : hres;

808
    hres = CreateUri(secur_url, Uri_CREATE_ALLOW_IMPLICIT_FILE_SCHEME, 0, &uri);
809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834
    CoTaskMemFree(secur_url);
    if(FAILED(hres))
        return hres;

    hres = generate_security_id(uri, secid, secid_len, zone);
    IUri_Release(uri);

    return hres;
}

static HRESULT get_security_id_for_uri(IUri *uri, BYTE *secid, DWORD *secid_len)
{
    HRESULT hres;
    IUri *secur_uri;
    DWORD zone = URLZONE_INVALID;

    hres = map_uri_to_zone(uri, &zone, &secur_uri);
    if(FAILED(hres))
        return hres;

    hres = generate_security_id(secur_uri, secid, secid_len, zone);
    IUri_Release(secur_uri);

    return hres;
}

835 836 837 838 839
/***********************************************************************
 *           InternetSecurityManager implementation
 *
 */
typedef struct {
840
    IInternetSecurityManagerEx2 IInternetSecurityManagerEx2_iface;
841 842 843 844 845 846 847

    LONG ref;

    IInternetSecurityMgrSite *mgrsite;
    IInternetSecurityManager *custom_manager;
} SecManagerImpl;

848
static inline SecManagerImpl *impl_from_IInternetSecurityManagerEx2(IInternetSecurityManagerEx2 *iface)
849
{
850
    return CONTAINING_RECORD(iface, SecManagerImpl, IInternetSecurityManagerEx2_iface);
851
}
852

853
static HRESULT WINAPI SecManagerImpl_QueryInterface(IInternetSecurityManagerEx2* iface,REFIID riid,void** ppvObject)
854
{
855
    SecManagerImpl *This = impl_from_IInternetSecurityManagerEx2(iface);
856 857 858 859 860 861 862 863 864 865 866 867

    TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppvObject);

    /* Perform a sanity check on the parameters.*/
    if ( (This==0) || (ppvObject==0) )
	return E_INVALIDARG;

    /* Initialize the return parameter */
    *ppvObject = 0;

    /* Compare the riid with the interface IDs implemented by this object.*/
    if (IsEqualIID(&IID_IUnknown, riid) ||
868 869 870
        IsEqualIID(&IID_IInternetSecurityManager, riid) ||
        IsEqualIID(&IID_IInternetSecurityManagerEx, riid) ||
        IsEqualIID(&IID_IInternetSecurityManagerEx2, riid))
871 872 873
        *ppvObject = iface;

    /* Check that we obtained an interface.*/
874 875
    if (!*ppvObject) {
        WARN("not supported interface %s\n", debugstr_guid(riid));
876
        return E_NOINTERFACE;
877
    }
878 879

    /* Query Interface always increases the reference count by one when it is successful */
880
    IInternetSecurityManager_AddRef(iface);
881 882 883 884

    return S_OK;
}

885
static ULONG WINAPI SecManagerImpl_AddRef(IInternetSecurityManagerEx2* iface)
886
{
887
    SecManagerImpl *This = impl_from_IInternetSecurityManagerEx2(iface);
888
    ULONG refCount = InterlockedIncrement(&This->ref);
889

890
    TRACE("(%p) ref=%u\n", This, refCount);
891

892
    return refCount;
893 894
}

895
static ULONG WINAPI SecManagerImpl_Release(IInternetSecurityManagerEx2* iface)
896
{
897
    SecManagerImpl *This = impl_from_IInternetSecurityManagerEx2(iface);
898
    ULONG refCount = InterlockedDecrement(&This->ref);
899

900
    TRACE("(%p) ref=%u\n", This, refCount);
901 902

    /* destroy the object if there's no more reference on it */
903
    if (!refCount){
904 905 906 907 908
        if(This->mgrsite)
            IInternetSecurityMgrSite_Release(This->mgrsite);
        if(This->custom_manager)
            IInternetSecurityManager_Release(This->custom_manager);

909
        heap_free(This);
910

Jacek Caban's avatar
Jacek Caban committed
911
        URLMON_UnlockModule();
912
    }
913

914
    return refCount;
915 916
}

917
static HRESULT WINAPI SecManagerImpl_SetSecuritySite(IInternetSecurityManagerEx2 *iface,
918 919
                                                     IInternetSecurityMgrSite *pSite)
{
920
    SecManagerImpl *This = impl_from_IInternetSecurityManagerEx2(iface);
921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949

    TRACE("(%p)->(%p)\n", This, pSite);

    if(This->mgrsite)
        IInternetSecurityMgrSite_Release(This->mgrsite);

    if(This->custom_manager) {
        IInternetSecurityManager_Release(This->custom_manager);
        This->custom_manager = NULL;
    }

    This->mgrsite = pSite;

    if(pSite) {
        IServiceProvider *servprov;
        HRESULT hres;

        IInternetSecurityMgrSite_AddRef(pSite);

        hres = IInternetSecurityMgrSite_QueryInterface(pSite, &IID_IServiceProvider,
                (void**)&servprov);
        if(SUCCEEDED(hres)) {
            IServiceProvider_QueryService(servprov, &SID_SInternetSecurityManager,
                    &IID_IInternetSecurityManager, (void**)&This->custom_manager);
            IServiceProvider_Release(servprov);
        }
    }

    return S_OK;
950 951
}

952
static HRESULT WINAPI SecManagerImpl_GetSecuritySite(IInternetSecurityManagerEx2 *iface,
953 954
                                                     IInternetSecurityMgrSite **ppSite)
{
955
    SecManagerImpl *This = impl_from_IInternetSecurityManagerEx2(iface);
956 957 958 959 960 961 962 963 964 965 966

    TRACE("(%p)->(%p)\n", This, ppSite);

    if(!ppSite)
        return E_INVALIDARG;

    if(This->mgrsite)
        IInternetSecurityMgrSite_AddRef(This->mgrsite);

    *ppSite = This->mgrsite;
    return S_OK;
967 968
}

969
static HRESULT WINAPI SecManagerImpl_MapUrlToZone(IInternetSecurityManagerEx2 *iface,
970 971 972
                                                  LPCWSTR pwszUrl, DWORD *pdwZone,
                                                  DWORD dwFlags)
{
973
    SecManagerImpl *This = impl_from_IInternetSecurityManagerEx2(iface);
974 975
    HRESULT hres;

976
    TRACE("(%p)->(%s %p %08x)\n", iface, debugstr_w(pwszUrl), pdwZone, dwFlags);
977 978 979 980 981 982 983 984

    if(This->custom_manager) {
        hres = IInternetSecurityManager_MapUrlToZone(This->custom_manager,
                pwszUrl, pdwZone, dwFlags);
        if(hres != INET_E_DEFAULT_ACTION)
            return hres;
    }

Jacek Caban's avatar
Jacek Caban committed
985
    if(!pwszUrl) {
986
        *pdwZone = URLZONE_INVALID;
987
        return E_INVALIDARG;
Jacek Caban's avatar
Jacek Caban committed
988
    }
989 990

    if(dwFlags)
991
        FIXME("not supported flags: %08x\n", dwFlags);
992

993
    return map_url_to_zone(pwszUrl, pdwZone, NULL);
994 995
}

996
static HRESULT WINAPI SecManagerImpl_GetSecurityId(IInternetSecurityManagerEx2 *iface,
997
        LPCWSTR pwszUrl, BYTE *pbSecurityId, DWORD *pcbSecurityId, DWORD_PTR dwReserved)
998
{
999
    SecManagerImpl *This = impl_from_IInternetSecurityManagerEx2(iface);
1000 1001 1002

    TRACE("(%p)->(%s %p %p %08lx)\n", iface, debugstr_w(pwszUrl), pbSecurityId,
          pcbSecurityId, dwReserved);
1003 1004

    if(This->custom_manager) {
1005 1006
        HRESULT hres;

1007 1008 1009 1010 1011 1012
        hres = IInternetSecurityManager_GetSecurityId(This->custom_manager,
                pwszUrl, pbSecurityId, pcbSecurityId, dwReserved);
        if(hres != INET_E_DEFAULT_ACTION)
            return hres;
    }

1013 1014 1015 1016 1017 1018
    if(!pwszUrl || !pbSecurityId || !pcbSecurityId)
        return E_INVALIDARG;

    if(dwReserved)
        FIXME("dwReserved is not supported\n");

1019
    return get_security_id_for_url(pwszUrl, pbSecurityId, pcbSecurityId);
1020 1021 1022
}


1023
static HRESULT WINAPI SecManagerImpl_ProcessUrlAction(IInternetSecurityManagerEx2 *iface,
1024 1025 1026 1027 1028
                                                      LPCWSTR pwszUrl, DWORD dwAction,
                                                      BYTE *pPolicy, DWORD cbPolicy,
                                                      BYTE *pContext, DWORD cbContext,
                                                      DWORD dwFlags, DWORD dwReserved)
{
1029
    SecManagerImpl *This = impl_from_IInternetSecurityManagerEx2(iface);
1030
    DWORD zone, policy;
1031 1032
    HRESULT hres;

1033
    TRACE("(%p)->(%s %08x %p %08x %p %08x %08x %08x)\n", iface, debugstr_w(pwszUrl), dwAction,
1034
          pPolicy, cbPolicy, pContext, cbContext, dwFlags, dwReserved);
1035 1036 1037 1038 1039 1040 1041 1042

    if(This->custom_manager) {
        hres = IInternetSecurityManager_ProcessUrlAction(This->custom_manager, pwszUrl, dwAction,
                pPolicy, cbPolicy, pContext, cbContext, dwFlags, dwReserved);
        if(hres != INET_E_DEFAULT_ACTION)
            return hres;
    }

1043
    if(dwFlags || dwReserved)
1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057
        FIXME("Unsupported arguments\n");

    if(!pwszUrl)
        return E_INVALIDARG;

    hres = map_url_to_zone(pwszUrl, &zone, NULL);
    if(FAILED(hres))
        return hres;

    hres = get_action_policy(zone, dwAction, (BYTE*)&policy, sizeof(policy), URLZONEREG_DEFAULT);
    if(FAILED(hres))
        return hres;

    TRACE("policy %x\n", policy);
1058 1059
    if(cbPolicy >= sizeof(DWORD))
        *(DWORD*)pPolicy = policy;
1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074

    switch(GetUrlPolicyPermissions(policy)) {
    case URLPOLICY_ALLOW:
    case URLPOLICY_CHANNEL_SOFTDIST_PRECACHE:
        return S_OK;
    case URLPOLICY_DISALLOW:
        return S_FALSE;
    case URLPOLICY_QUERY:
        FIXME("URLPOLICY_QUERY not implemented\n");
        return E_FAIL;
    default:
        FIXME("Not implemented policy %x\n", policy);
    }

    return E_FAIL;
1075 1076 1077
}
                                               

1078
static HRESULT WINAPI SecManagerImpl_QueryCustomPolicy(IInternetSecurityManagerEx2 *iface,
1079 1080 1081 1082 1083
                                                       LPCWSTR pwszUrl, REFGUID guidKey,
                                                       BYTE **ppPolicy, DWORD *pcbPolicy,
                                                       BYTE *pContext, DWORD cbContext,
                                                       DWORD dwReserved)
{
1084
    SecManagerImpl *This = impl_from_IInternetSecurityManagerEx2(iface);
1085 1086
    HRESULT hres;

1087
    TRACE("(%p)->(%s %s %p %p %p %08x %08x )\n", iface, debugstr_w(pwszUrl), debugstr_guid(guidKey),
1088
          ppPolicy, pcbPolicy, pContext, cbContext, dwReserved);
1089 1090 1091 1092 1093 1094 1095 1096

    if(This->custom_manager) {
        hres = IInternetSecurityManager_QueryCustomPolicy(This->custom_manager, pwszUrl, guidKey,
                ppPolicy, pcbPolicy, pContext, cbContext, dwReserved);
        if(hres != INET_E_DEFAULT_ACTION)
            return hres;
    }

1097 1098
    WARN("Unknown guidKey %s\n", debugstr_guid(guidKey));
    return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
1099 1100
}

1101
static HRESULT WINAPI SecManagerImpl_SetZoneMapping(IInternetSecurityManagerEx2 *iface,
1102 1103
                                                    DWORD dwZone, LPCWSTR pwszPattern, DWORD dwFlags)
{
1104
    SecManagerImpl *This = impl_from_IInternetSecurityManagerEx2(iface);
1105 1106
    HRESULT hres;

1107
    TRACE("(%p)->(%08x %s %08x)\n", iface, dwZone, debugstr_w(pwszPattern),dwFlags);
1108 1109 1110 1111 1112 1113 1114 1115 1116

    if(This->custom_manager) {
        hres = IInternetSecurityManager_SetZoneMapping(This->custom_manager, dwZone,
                pwszPattern, dwFlags);
        if(hres != INET_E_DEFAULT_ACTION)
            return hres;
    }

    FIXME("Default action is not implemented\n");
1117 1118 1119
    return E_NOTIMPL;
}

1120
static HRESULT WINAPI SecManagerImpl_GetZoneMappings(IInternetSecurityManagerEx2 *iface,
1121
        DWORD dwZone, IEnumString **ppenumString, DWORD dwFlags)
1122
{
1123
    SecManagerImpl *This = impl_from_IInternetSecurityManagerEx2(iface);
1124 1125
    HRESULT hres;

1126
    TRACE("(%p)->(%08x %p %08x)\n", iface, dwZone, ppenumString,dwFlags);
1127 1128 1129 1130 1131 1132 1133 1134 1135

    if(This->custom_manager) {
        hres = IInternetSecurityManager_GetZoneMappings(This->custom_manager, dwZone,
                ppenumString, dwFlags);
        if(hres != INET_E_DEFAULT_ACTION)
            return hres;
    }

    FIXME("Default action is not implemented\n");
1136 1137 1138
    return E_NOTIMPL;
}

1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152
static HRESULT WINAPI SecManagerImpl_ProcessUrlActionEx(IInternetSecurityManagerEx2 *iface,
        LPCWSTR pwszUrl, DWORD dwAction, BYTE *pPolicy, DWORD cbPolicy, BYTE *pContext, DWORD cbContext,
        DWORD dwFlags, DWORD dwReserved, DWORD *pdwOutFlags)
{
    SecManagerImpl *This = impl_from_IInternetSecurityManagerEx2(iface);
    FIXME("(%p)->(%s %08x %p %d %p %d %08x %08x %p) stub\n", This, debugstr_w(pwszUrl), dwAction, pPolicy, cbPolicy,
          pContext, cbContext, dwFlags, dwReserved, pdwOutFlags);
    return E_NOTIMPL;
}

static HRESULT WINAPI SecManagerImpl_MapUrlToZoneEx2(IInternetSecurityManagerEx2 *iface,
        IUri *pUri, DWORD *pdwZone, DWORD dwFlags, LPWSTR *ppwszMappedUrl, DWORD *pdwOutFlags)
{
    SecManagerImpl *This = impl_from_IInternetSecurityManagerEx2(iface);
1153 1154 1155

    TRACE("(%p)->(%p %p %08x %p %p)\n", This, pUri, pdwZone, dwFlags, ppwszMappedUrl, pdwOutFlags);

1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179
    if(This->custom_manager) {
        HRESULT hres;
        IInternetSecurityManagerEx2 *sec_mgr2;

        hres = IInternetSecurityManager_QueryInterface(This->custom_manager, &IID_IInternetSecurityManagerEx2,
                (void**)&sec_mgr2);
        if(SUCCEEDED(hres)) {
            hres = IInternetSecurityManagerEx2_MapUrlToZoneEx2(sec_mgr2, pUri, pdwZone, dwFlags, ppwszMappedUrl, pdwOutFlags);
            IInternetSecurityManagerEx2_Release(sec_mgr2);
        } else {
            BSTR url;

            hres = IUri_GetDisplayUri(pUri, &url);
            if(FAILED(hres))
                return hres;

            hres = IInternetSecurityManager_MapUrlToZone(This->custom_manager, url, pdwZone, dwFlags);
            SysFreeString(url);
        }

        if(hres != INET_E_DEFAULT_ACTION)
            return hres;
    }

1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190
    if(!pdwZone)
        return E_INVALIDARG;

    if(!pUri) {
        *pdwZone = URLZONE_INVALID;
        return E_INVALIDARG;
    }

    if(dwFlags)
        FIXME("Unsupported flags: %08x\n", dwFlags);

1191
    return map_uri_to_zone(pUri, pdwZone, NULL);
1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207
}

static HRESULT WINAPI SecManagerImpl_ProcessUrlActionEx2(IInternetSecurityManagerEx2 *iface,
        IUri *pUri, DWORD dwAction, BYTE *pPolicy, DWORD cbPolicy, BYTE *pContext, DWORD cbContext,
        DWORD dwFlags, DWORD_PTR dwReserved, DWORD *pdwOutFlags)
{
    SecManagerImpl *This = impl_from_IInternetSecurityManagerEx2(iface);
    FIXME("(%p)->(%p %08x %p %d %p %d %08x %08x %p) stub\n", This, pUri, dwAction, pPolicy,
          cbPolicy, pContext, cbContext, dwFlags, (DWORD)dwReserved, pdwOutFlags);
    return E_NOTIMPL;
}

static HRESULT WINAPI SecManagerImpl_GetSecurityIdEx2(IInternetSecurityManagerEx2 *iface,
        IUri *pUri, BYTE *pbSecurityId, DWORD *pcbSecurityId, DWORD_PTR dwReserved)
{
    SecManagerImpl *This = impl_from_IInternetSecurityManagerEx2(iface);
1208 1209 1210 1211 1212 1213 1214 1215 1216
    TRACE("(%p)->(%p %p %p %08x) stub\n", This, pUri, pbSecurityId, pcbSecurityId, (DWORD)dwReserved);

    if(dwReserved)
        FIXME("dwReserved is not supported yet\n");

    if(!pUri || !pcbSecurityId || !pbSecurityId)
        return E_INVALIDARG;

    return get_security_id_for_uri(pUri, pbSecurityId, pcbSecurityId);
1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229
}

static HRESULT WINAPI SecManagerImpl_QueryCustomPolicyEx2(IInternetSecurityManagerEx2 *iface,
        IUri *pUri, REFGUID guidKey, BYTE **ppPolicy, DWORD *pcbPolicy, BYTE *pContext,
        DWORD cbContext, DWORD_PTR dwReserved)
{
    SecManagerImpl *This = impl_from_IInternetSecurityManagerEx2(iface);
    FIXME("(%p)->(%p %s %p %p %p %d %08x) stub\n", This, pUri, debugstr_guid(guidKey), ppPolicy, pcbPolicy,
          pContext, cbContext, (DWORD)dwReserved);
    return E_NOTIMPL;
}

static const IInternetSecurityManagerEx2Vtbl VT_SecManagerImpl =
1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240
{
    SecManagerImpl_QueryInterface,
    SecManagerImpl_AddRef,
    SecManagerImpl_Release,
    SecManagerImpl_SetSecuritySite,
    SecManagerImpl_GetSecuritySite,
    SecManagerImpl_MapUrlToZone,
    SecManagerImpl_GetSecurityId,
    SecManagerImpl_ProcessUrlAction,
    SecManagerImpl_QueryCustomPolicy,
    SecManagerImpl_SetZoneMapping,
1241 1242 1243 1244 1245 1246
    SecManagerImpl_GetZoneMappings,
    SecManagerImpl_ProcessUrlActionEx,
    SecManagerImpl_MapUrlToZoneEx2,
    SecManagerImpl_ProcessUrlActionEx2,
    SecManagerImpl_GetSecurityIdEx2,
    SecManagerImpl_QueryCustomPolicyEx2
1247 1248 1249 1250 1251 1252 1253
};

HRESULT SecManagerImpl_Construct(IUnknown *pUnkOuter, LPVOID *ppobj)
{
    SecManagerImpl *This;

    TRACE("(%p,%p)\n",pUnkOuter,ppobj);
1254
    This = heap_alloc(sizeof(*This));
1255 1256

    /* Initialize the virtual function table. */
1257
    This->IInternetSecurityManagerEx2_iface.lpVtbl = &VT_SecManagerImpl;
1258 1259 1260 1261

    This->ref = 1;
    This->mgrsite = NULL;
    This->custom_manager = NULL;
1262 1263

    *ppobj = This;
Jacek Caban's avatar
Jacek Caban committed
1264 1265 1266

    URLMON_LockModule();

1267 1268 1269 1270 1271 1272 1273 1274
    return S_OK;
}

/***********************************************************************
 *           InternetZoneManager implementation
 *
 */
typedef struct {
1275
    IInternetZoneManagerEx2 IInternetZoneManagerEx2_iface;
1276
    LONG ref;
1277 1278
    LPDWORD *zonemaps;
    DWORD zonemap_count;
1279 1280
} ZoneMgrImpl;

1281 1282 1283 1284 1285
static inline ZoneMgrImpl *impl_from_IInternetZoneManagerEx2(IInternetZoneManagerEx2 *iface)
{
    return CONTAINING_RECORD(iface, ZoneMgrImpl, IInternetZoneManagerEx2_iface);
}

1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297

/***********************************************************************
 * build_zonemap_from_reg [internal]
 *
 * Enumerate the Zones in the Registry and return the Zones in a DWORD-array
 * The number of the Zones is returned in data[0]
 */
static LPDWORD build_zonemap_from_reg(void)
{
    WCHAR name[32];
    HKEY hkey;
    LPDWORD data = NULL;
1298
    DWORD allocated = 6; /* space for the zonecount and Zone "0" up to Zone "4" */
1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344
    DWORD used = 0;
    DWORD res;
    DWORD len;


    res = RegOpenKeyW(HKEY_CURRENT_USER, wszZonesKey, &hkey);
    if (res)
        return NULL;

    data = heap_alloc(allocated * sizeof(DWORD));
    if (!data)
        goto cleanup;

    while (!res) {
        name[0] = '\0';
        len = sizeof(name) / sizeof(name[0]);
        res = RegEnumKeyExW(hkey, used, name, &len, NULL, NULL, NULL, NULL);

        if (!res) {
            used++;
            if (used == allocated) {
                LPDWORD new_data;

                allocated *= 2;
                new_data = heap_realloc_zero(data, allocated * sizeof(DWORD));
                if (!new_data)
                    goto cleanup;

                data = new_data;
            }
            data[used] = atoiW(name);
        }
    }
    if (used) {
        RegCloseKey(hkey);
        data[0] = used;
        return data;
    }

cleanup:
    /* something failed */
    RegCloseKey(hkey);
    heap_free(data);
    return NULL;
}

1345 1346 1347
/********************************************************************
 *      IInternetZoneManager_QueryInterface
 */
1348
static HRESULT WINAPI ZoneMgrImpl_QueryInterface(IInternetZoneManagerEx2* iface, REFIID riid, void** ppvObject)
1349
{
1350
    ZoneMgrImpl* This = impl_from_IInternetZoneManagerEx2(iface);
1351 1352 1353 1354 1355 1356

    TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(riid), ppvObject);

    if(!This || !ppvObject)
        return E_INVALIDARG;

1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367
    if(IsEqualIID(&IID_IUnknown, riid)) {
        TRACE("(%p)->(IID_IUnknown %p)\n", This, ppvObject);
    }else if(IsEqualIID(&IID_IInternetZoneManager, riid)) {
        TRACE("(%p)->(IID_InternetZoneManager %p)\n", This, ppvObject);
    }else if(IsEqualIID(&IID_IInternetZoneManagerEx, riid)) {
        TRACE("(%p)->(IID_InternetZoneManagerEx %p)\n", This, ppvObject);
    }else if(IsEqualIID(&IID_IInternetZoneManagerEx2, riid)) {
        TRACE("(%p)->(IID_InternetZoneManagerEx2 %p)\n", This, ppvObject);
    }
    else
    {
1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380
        FIXME("Unknown interface: %s\n", debugstr_guid(riid));
        *ppvObject = NULL;
        return E_NOINTERFACE;
    }

    *ppvObject = iface;
    IInternetZoneManager_AddRef(iface);
    return S_OK;
}

/********************************************************************
 *      IInternetZoneManager_AddRef
 */
1381
static ULONG WINAPI ZoneMgrImpl_AddRef(IInternetZoneManagerEx2* iface)
1382
{
1383
    ZoneMgrImpl* This = impl_from_IInternetZoneManagerEx2(iface);
1384
    ULONG refCount = InterlockedIncrement(&This->ref);
1385

1386
    TRACE("(%p)->(ref before=%u)\n",This, refCount - 1);
1387

1388
    return refCount;
1389 1390 1391 1392 1393
}

/********************************************************************
 *      IInternetZoneManager_Release
 */
1394
static ULONG WINAPI ZoneMgrImpl_Release(IInternetZoneManagerEx2* iface)
1395
{
1396
    ZoneMgrImpl* This = impl_from_IInternetZoneManagerEx2(iface);
1397
    ULONG refCount = InterlockedDecrement(&This->ref);
1398

1399
    TRACE("(%p)->(ref before=%u)\n",This, refCount + 1);
1400

Jacek Caban's avatar
Jacek Caban committed
1401
    if(!refCount) {
1402 1403
        while (This->zonemap_count) heap_free(This->zonemaps[--This->zonemap_count]);
        heap_free(This->zonemaps);
1404
        heap_free(This);
Jacek Caban's avatar
Jacek Caban committed
1405 1406
        URLMON_UnlockModule();
    }
1407
    
1408
    return refCount;
1409 1410 1411 1412 1413
}

/********************************************************************
 *      IInternetZoneManager_GetZoneAttributes
 */
1414
static HRESULT WINAPI ZoneMgrImpl_GetZoneAttributes(IInternetZoneManagerEx2* iface,
1415 1416 1417
                                                    DWORD dwZone,
                                                    ZONEATTRIBUTES* pZoneAttributes)
{
1418
    ZoneMgrImpl* This = impl_from_IInternetZoneManagerEx2(iface);
1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446
    HRESULT hr;
    HKEY hcu;
    HKEY hklm = NULL;

    TRACE("(%p)->(%d %p)\n", This, dwZone, pZoneAttributes);

    if (!pZoneAttributes)
        return E_INVALIDARG;

    hr = open_zone_key(HKEY_CURRENT_USER, dwZone, &hcu);
    if (FAILED(hr))
        return S_OK;  /* IE6 and older returned E_FAIL here */

    hr = open_zone_key(HKEY_LOCAL_MACHINE, dwZone, &hklm);
    if (FAILED(hr))
        TRACE("Zone %d not in HKLM\n", dwZone);

    get_string_from_reg(hcu, hklm, displaynameW, pZoneAttributes->szDisplayName, MAX_ZONE_PATH);
    get_string_from_reg(hcu, hklm, descriptionW, pZoneAttributes->szDescription, MAX_ZONE_DESCRIPTION);
    get_string_from_reg(hcu, hklm, iconW, pZoneAttributes->szIconPath, MAX_ZONE_PATH);
    get_dword_from_reg(hcu, hklm, minlevelW, &pZoneAttributes->dwTemplateMinLevel);
    get_dword_from_reg(hcu, hklm, currentlevelW, &pZoneAttributes->dwTemplateCurrentLevel);
    get_dword_from_reg(hcu, hklm, recommendedlevelW, &pZoneAttributes->dwTemplateRecommended);
    get_dword_from_reg(hcu, hklm, flagsW, &pZoneAttributes->dwFlags);

    RegCloseKey(hklm);
    RegCloseKey(hcu);
    return S_OK;
1447 1448 1449 1450 1451
}

/********************************************************************
 *      IInternetZoneManager_SetZoneAttributes
 */
1452
static HRESULT WINAPI ZoneMgrImpl_SetZoneAttributes(IInternetZoneManagerEx2* iface,
1453 1454 1455
                                                    DWORD dwZone,
                                                    ZONEATTRIBUTES* pZoneAttributes)
{
1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491
    ZoneMgrImpl* This = impl_from_IInternetZoneManagerEx2(iface);
    HRESULT hr;
    HKEY hcu;

    TRACE("(%p)->(%d %p)\n", This, dwZone, pZoneAttributes);

    if (!pZoneAttributes)
        return E_INVALIDARG;

    hr = open_zone_key(HKEY_CURRENT_USER, dwZone, &hcu);
    if (FAILED(hr))
        return S_OK;  /* IE6 returned E_FAIL here */

    /* cbSize is ignored */
    RegSetValueExW(hcu, displaynameW, 0, REG_SZ, (LPBYTE) pZoneAttributes->szDisplayName,
                    (lstrlenW(pZoneAttributes->szDisplayName)+1)* sizeof(WCHAR));

    RegSetValueExW(hcu, descriptionW, 0, REG_SZ, (LPBYTE) pZoneAttributes->szDescription,
                    (lstrlenW(pZoneAttributes->szDescription)+1)* sizeof(WCHAR));

    RegSetValueExW(hcu, iconW, 0, REG_SZ, (LPBYTE) pZoneAttributes->szIconPath,
                    (lstrlenW(pZoneAttributes->szIconPath)+1)* sizeof(WCHAR));

    RegSetValueExW(hcu, minlevelW, 0, REG_DWORD,
                    (const BYTE*) &pZoneAttributes->dwTemplateMinLevel, sizeof(DWORD));

    RegSetValueExW(hcu, currentlevelW, 0, REG_DWORD,
                    (const BYTE*) &pZoneAttributes->dwTemplateCurrentLevel, sizeof(DWORD));

    RegSetValueExW(hcu, recommendedlevelW, 0, REG_DWORD,
                    (const BYTE*) &pZoneAttributes->dwTemplateRecommended, sizeof(DWORD));

    RegSetValueExW(hcu, flagsW, 0, REG_DWORD, (const BYTE*) &pZoneAttributes->dwFlags, sizeof(DWORD));
    RegCloseKey(hcu);
    return S_OK;

1492 1493 1494 1495 1496
}

/********************************************************************
 *      IInternetZoneManager_GetZoneCustomPolicy
 */
1497
static HRESULT WINAPI ZoneMgrImpl_GetZoneCustomPolicy(IInternetZoneManagerEx2* iface,
1498 1499 1500 1501 1502 1503
                                                      DWORD dwZone,
                                                      REFGUID guidKey,
                                                      BYTE** ppPolicy,
                                                      DWORD* pcbPolicy,
                                                      URLZONEREG ulrZoneReg)
{
1504
    FIXME("(%p)->(%08x %s %p %p %08x) stub\n", iface, dwZone, debugstr_guid(guidKey),
1505 1506 1507 1508 1509 1510 1511
                                                    ppPolicy, pcbPolicy, ulrZoneReg);
    return E_NOTIMPL;
}

/********************************************************************
 *      IInternetZoneManager_SetZoneCustomPolicy
 */
1512
static HRESULT WINAPI ZoneMgrImpl_SetZoneCustomPolicy(IInternetZoneManagerEx2* iface,
1513 1514 1515 1516 1517 1518
                                                      DWORD dwZone,
                                                      REFGUID guidKey,
                                                      BYTE* ppPolicy,
                                                      DWORD cbPolicy,
                                                      URLZONEREG ulrZoneReg)
{
1519
    FIXME("(%p)->(%08x %s %p %08x %08x) stub\n", iface, dwZone, debugstr_guid(guidKey),
1520 1521 1522 1523 1524 1525 1526
                                                    ppPolicy, cbPolicy, ulrZoneReg);
    return E_NOTIMPL;
}

/********************************************************************
 *      IInternetZoneManager_GetZoneActionPolicy
 */
1527
static HRESULT WINAPI ZoneMgrImpl_GetZoneActionPolicy(IInternetZoneManagerEx2* iface,
1528
        DWORD dwZone, DWORD dwAction, BYTE* pPolicy, DWORD cbPolicy, URLZONEREG urlZoneReg)
1529
{
1530
    TRACE("(%p)->(%d %08x %p %d %d)\n", iface, dwZone, dwAction, pPolicy,
1531 1532 1533 1534 1535
            cbPolicy, urlZoneReg);

    if(!pPolicy)
        return E_INVALIDARG;

1536
    return get_action_policy(dwZone, dwAction, pPolicy, cbPolicy, urlZoneReg);
1537 1538 1539 1540 1541
}

/********************************************************************
 *      IInternetZoneManager_SetZoneActionPolicy
 */
1542
static HRESULT WINAPI ZoneMgrImpl_SetZoneActionPolicy(IInternetZoneManagerEx2* iface,
1543 1544 1545 1546 1547 1548
                                                      DWORD dwZone,
                                                      DWORD dwAction,
                                                      BYTE* pPolicy,
                                                      DWORD cbPolicy,
                                                      URLZONEREG urlZoneReg)
{
1549
    FIXME("(%p)->(%08x %08x %p %08x %08x) stub\n", iface, dwZone, dwAction, pPolicy,
1550 1551 1552 1553
                                                       cbPolicy, urlZoneReg);
    return E_NOTIMPL;
}

1554 1555 1556
/********************************************************************
 *      IInternetZoneManager_PromptAction
 */
1557
static HRESULT WINAPI ZoneMgrImpl_PromptAction(IInternetZoneManagerEx2* iface,
1558 1559 1560 1561 1562 1563
                                               DWORD dwAction,
                                               HWND hwndParent,
                                               LPCWSTR pwszUrl,
                                               LPCWSTR pwszText,
                                               DWORD dwPromptFlags)
{
1564
    FIXME("%p %08x %p %s %s %08x\n", iface, dwAction, hwndParent,
1565 1566 1567 1568
          debugstr_w(pwszUrl), debugstr_w(pwszText), dwPromptFlags );
    return E_NOTIMPL;
}

1569 1570 1571
/********************************************************************
 *      IInternetZoneManager_LogAction
 */
1572
static HRESULT WINAPI ZoneMgrImpl_LogAction(IInternetZoneManagerEx2* iface,
1573 1574 1575 1576 1577
                                            DWORD dwAction,
                                            LPCWSTR pwszUrl,
                                            LPCWSTR pwszText,
                                            DWORD dwLogFlags)
{
1578
    FIXME("(%p)->(%08x %s %s %08x) stub\n", iface, dwAction, debugstr_w(pwszUrl),
1579 1580 1581 1582 1583 1584 1585
                                              debugstr_w(pwszText), dwLogFlags);
    return E_NOTIMPL;
}

/********************************************************************
 *      IInternetZoneManager_CreateZoneEnumerator
 */
1586
static HRESULT WINAPI ZoneMgrImpl_CreateZoneEnumerator(IInternetZoneManagerEx2* iface,
1587 1588 1589 1590
                                                       DWORD* pdwEnum,
                                                       DWORD* pdwCount,
                                                       DWORD dwFlags)
{
1591
    ZoneMgrImpl* This = impl_from_IInternetZoneManagerEx2(iface);
1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635
    LPDWORD * new_maps;
    LPDWORD data;
    DWORD i;

    TRACE("(%p)->(%p, %p, 0x%08x)\n", This, pdwEnum, pdwCount, dwFlags);
    if (!pdwEnum || !pdwCount || (dwFlags != 0))
        return E_INVALIDARG;

    data = build_zonemap_from_reg();
    TRACE("found %d zones\n", data ? data[0] : -1);

    if (!data)
        return E_FAIL;

    for (i = 0; i < This->zonemap_count; i++) {
        if (This->zonemaps && !This->zonemaps[i]) {
            This->zonemaps[i] = data;
            *pdwEnum = i;
            *pdwCount = data[0];
            return S_OK;
        }
    }

    if (This->zonemaps) {
        /* try to double the nr. of pointers in the array */
        new_maps = heap_realloc_zero(This->zonemaps, This->zonemap_count * 2 * sizeof(LPDWORD));
        if (new_maps)
            This->zonemap_count *= 2;
    }
    else
    {
        This->zonemap_count = 2;
        new_maps = heap_alloc_zero(This->zonemap_count * sizeof(LPDWORD));
    }

    if (!new_maps) {
        heap_free(data);
        return E_FAIL;
    }
    This->zonemaps = new_maps;
    This->zonemaps[i] = data;
    *pdwEnum = i;
    *pdwCount = data[0];
    return S_OK;
1636 1637 1638 1639 1640
}

/********************************************************************
 *      IInternetZoneManager_GetZoneAt
 */
1641
static HRESULT WINAPI ZoneMgrImpl_GetZoneAt(IInternetZoneManagerEx2* iface,
1642 1643 1644 1645
                                            DWORD dwEnum,
                                            DWORD dwIndex,
                                            DWORD* pdwZone)
{
1646
    ZoneMgrImpl* This = impl_from_IInternetZoneManagerEx2(iface);
1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660
    LPDWORD data;

    TRACE("(%p)->(0x%08x, %d, %p)\n", This, dwEnum, dwIndex, pdwZone);

    /* make sure, that dwEnum and dwIndex are in the valid range */
    if (dwEnum < This->zonemap_count) {
        if ((data = This->zonemaps[dwEnum])) {
            if (dwIndex < data[0]) {
                *pdwZone = data[dwIndex + 1];
                return S_OK;
            }
        }
    }
    return E_INVALIDARG;
1661 1662 1663 1664 1665
}

/********************************************************************
 *      IInternetZoneManager_DestroyZoneEnumerator
 */
1666
static HRESULT WINAPI ZoneMgrImpl_DestroyZoneEnumerator(IInternetZoneManagerEx2* iface,
1667 1668
                                                        DWORD dwEnum)
{
1669
    ZoneMgrImpl* This = impl_from_IInternetZoneManagerEx2(iface);
1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681
    LPDWORD data;

    TRACE("(%p)->(0x%08x)\n", This, dwEnum);
    /* make sure, that dwEnum is valid */
    if (dwEnum < This->zonemap_count) {
        if ((data = This->zonemaps[dwEnum])) {
            This->zonemaps[dwEnum] = NULL;
            heap_free(data);
            return S_OK;
        }
    }
    return E_INVALIDARG;
1682 1683 1684 1685 1686
}

/********************************************************************
 *      IInternetZoneManager_CopyTemplatePoliciesToZone
 */
1687
static HRESULT WINAPI ZoneMgrImpl_CopyTemplatePoliciesToZone(IInternetZoneManagerEx2* iface,
1688 1689 1690 1691
                                                             DWORD dwTemplate,
                                                             DWORD dwZone,
                                                             DWORD dwReserved)
{
1692
    FIXME("(%p)->(%08x %08x %08x) stub\n", iface, dwTemplate, dwZone, dwReserved);
1693 1694 1695
    return E_NOTIMPL;
}

1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800
/********************************************************************
 *      IInternetZoneManagerEx_GetZoneActionPolicyEx
 */
static HRESULT WINAPI ZoneMgrImpl_GetZoneActionPolicyEx(IInternetZoneManagerEx2* iface,
                                                        DWORD dwZone,
                                                        DWORD dwAction,
                                                        BYTE* pPolicy,
                                                        DWORD cbPolicy,
                                                        URLZONEREG urlZoneReg,
                                                        DWORD dwFlags)
{
    TRACE("(%p)->(%d, 0x%x, %p, %d, %d, 0x%x)\n", iface, dwZone,
            dwAction, pPolicy, cbPolicy, urlZoneReg, dwFlags);

    if(!pPolicy)
        return E_INVALIDARG;

    if (dwFlags)
        FIXME("dwFlags 0x%x ignored\n", dwFlags);

    return get_action_policy(dwZone, dwAction, pPolicy, cbPolicy, urlZoneReg);
}

/********************************************************************
 *      IInternetZoneManagerEx_SetZoneActionPolicyEx
 */
static HRESULT WINAPI ZoneMgrImpl_SetZoneActionPolicyEx(IInternetZoneManagerEx2* iface,
                                                        DWORD dwZone,
                                                        DWORD dwAction,
                                                        BYTE* pPolicy,
                                                        DWORD cbPolicy,
                                                        URLZONEREG urlZoneReg,
                                                        DWORD dwFlags)
{
    FIXME("(%p)->(%d, 0x%x, %p, %d, %d, 0x%x) stub\n", iface, dwZone, dwAction, pPolicy,
                                                       cbPolicy, urlZoneReg, dwFlags);
    return E_NOTIMPL;
}

/********************************************************************
 *      IInternetZoneManagerEx2_GetZoneAttributesEx
 */
static HRESULT WINAPI ZoneMgrImpl_GetZoneAttributesEx(IInternetZoneManagerEx2* iface,
                                                      DWORD dwZone,
                                                      ZONEATTRIBUTES* pZoneAttributes,
                                                      DWORD dwFlags)
{
    TRACE("(%p)->(%d, %p, 0x%x)\n", iface, dwZone, pZoneAttributes, dwFlags);

    if (dwFlags)
        FIXME("dwFlags 0x%x ignored\n", dwFlags);

    return IInternetZoneManager_GetZoneAttributes(iface, dwZone, pZoneAttributes);
}


/********************************************************************
 *      IInternetZoneManagerEx2_GetZoneSecurityState
 */
static HRESULT WINAPI ZoneMgrImpl_GetZoneSecurityState(IInternetZoneManagerEx2* iface,
                                                       DWORD dwZoneIndex,
                                                       BOOL fRespectPolicy,
                                                       LPDWORD pdwState,
                                                       BOOL *pfPolicyEncountered)
{
    FIXME("(%p)->(%d, %d, %p, %p) stub\n", iface, dwZoneIndex, fRespectPolicy,
                                           pdwState, pfPolicyEncountered);

    *pdwState = SECURITY_IE_STATE_GREEN;

    if (pfPolicyEncountered)
        *pfPolicyEncountered = FALSE;

    return S_OK;
}

/********************************************************************
 *      IInternetZoneManagerEx2_GetIESecurityState
 */
static HRESULT WINAPI ZoneMgrImpl_GetIESecurityState(IInternetZoneManagerEx2* iface,
                                                     BOOL fRespectPolicy,
                                                     LPDWORD pdwState,
                                                     BOOL *pfPolicyEncountered,
                                                     BOOL fNoCache)
{
    FIXME("(%p)->(%d, %p, %p, %d) stub\n", iface, fRespectPolicy, pdwState,
                                           pfPolicyEncountered, fNoCache);

    *pdwState = SECURITY_IE_STATE_GREEN;

    if (pfPolicyEncountered)
        *pfPolicyEncountered = FALSE;

    return S_OK;
}

/********************************************************************
 *      IInternetZoneManagerEx2_FixInsecureSettings
 */
static HRESULT WINAPI ZoneMgrImpl_FixInsecureSettings(IInternetZoneManagerEx2* iface)
{
    FIXME("(%p) stub\n", iface);
    return S_OK;
}

1801 1802 1803
/********************************************************************
 *      IInternetZoneManager_Construct
 */
1804
static const IInternetZoneManagerEx2Vtbl ZoneMgrImplVtbl = {
1805 1806 1807
    ZoneMgrImpl_QueryInterface,
    ZoneMgrImpl_AddRef,
    ZoneMgrImpl_Release,
1808
    /* IInternetZoneManager */
1809 1810 1811 1812 1813 1814
    ZoneMgrImpl_GetZoneAttributes,
    ZoneMgrImpl_SetZoneAttributes,
    ZoneMgrImpl_GetZoneCustomPolicy,
    ZoneMgrImpl_SetZoneCustomPolicy,
    ZoneMgrImpl_GetZoneActionPolicy,
    ZoneMgrImpl_SetZoneActionPolicy,
1815
    ZoneMgrImpl_PromptAction,
1816 1817 1818 1819 1820
    ZoneMgrImpl_LogAction,
    ZoneMgrImpl_CreateZoneEnumerator,
    ZoneMgrImpl_GetZoneAt,
    ZoneMgrImpl_DestroyZoneEnumerator,
    ZoneMgrImpl_CopyTemplatePoliciesToZone,
1821 1822 1823 1824 1825 1826 1827 1828
    /* IInternetZoneManagerEx */
    ZoneMgrImpl_GetZoneActionPolicyEx,
    ZoneMgrImpl_SetZoneActionPolicyEx,
    /* IInternetZoneManagerEx2 */
    ZoneMgrImpl_GetZoneAttributesEx,
    ZoneMgrImpl_GetZoneSecurityState,
    ZoneMgrImpl_GetIESecurityState,
    ZoneMgrImpl_FixInsecureSettings,
1829
};
1830

1831 1832
HRESULT ZoneMgrImpl_Construct(IUnknown *pUnkOuter, LPVOID *ppobj)
{
1833
    ZoneMgrImpl* ret = heap_alloc_zero(sizeof(ZoneMgrImpl));
1834 1835

    TRACE("(%p %p)\n", pUnkOuter, ppobj);
1836
    ret->IInternetZoneManagerEx2_iface.lpVtbl = &ZoneMgrImplVtbl;
1837
    ret->ref = 1;
1838
    *ppobj = (IInternetZoneManagerEx*)ret;
1839

Jacek Caban's avatar
Jacek Caban committed
1840 1841
    URLMON_LockModule();

1842 1843 1844
    return S_OK;
}

1845 1846 1847 1848 1849 1850 1851
/***********************************************************************
 *           CoInternetCreateSecurityManager (URLMON.@)
 *
 */
HRESULT WINAPI CoInternetCreateSecurityManager( IServiceProvider *pSP,
    IInternetSecurityManager **ppSM, DWORD dwReserved )
{
1852
    TRACE("%p %p %d\n", pSP, ppSM, dwReserved );
1853 1854 1855 1856

    if(pSP)
        FIXME("pSP not supported\n");

1857 1858
    return SecManagerImpl_Construct(NULL, (void**) ppSM);
}
1859 1860 1861 1862 1863 1864

/********************************************************************
 *      CoInternetCreateZoneManager (URLMON.@)
 */
HRESULT WINAPI CoInternetCreateZoneManager(IServiceProvider* pSP, IInternetZoneManager** ppZM, DWORD dwReserved)
{
1865
    TRACE("(%p %p %x)\n", pSP, ppZM, dwReserved);
1866 1867
    return ZoneMgrImpl_Construct(NULL, (void**)ppZM);
}
1868

1869 1870 1871 1872 1873
static HRESULT parse_security_url(const WCHAR *url, PSUACTION action, WCHAR **result) {
    IInternetProtocolInfo *protocol_info;
    WCHAR *tmp, *new_url = NULL, *alloc_url = NULL;
    DWORD size, new_size;
    HRESULT hres = S_OK, parse_hres;
1874

1875 1876
    while(1) {
        TRACE("parsing %s\n", debugstr_w(url));
1877

1878 1879 1880
        protocol_info = get_protocol_info(url);
        if(!protocol_info)
            break;
1881

1882 1883 1884 1885
        size = strlenW(url)+1;
        new_url = CoTaskMemAlloc(size*sizeof(WCHAR));
        if(!new_url) {
            hres = E_OUTOFMEMORY;
1886
            break;
1887
        }
1888

1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908
        new_size = 0;
        parse_hres = IInternetProtocolInfo_ParseUrl(protocol_info, url, PARSE_SECURITY_URL, 0, new_url, size, &new_size, 0);
        if(parse_hres == S_FALSE) {
            if(!new_size) {
                hres = E_UNEXPECTED;
                break;
            }

            tmp = CoTaskMemRealloc(new_url, new_size*sizeof(WCHAR));
            if(!tmp) {
                hres = E_OUTOFMEMORY;
                break;
            }
            new_url = tmp;
            parse_hres = IInternetProtocolInfo_ParseUrl(protocol_info, url, PARSE_SECURITY_URL, 0, new_url,
                    new_size, &new_size, 0);
            if(parse_hres == S_FALSE) {
                hres = E_FAIL;
                break;
            }
1909
        }
1910

1911 1912
        if(parse_hres != S_OK || !strcmpW(url, new_url))
            break;
1913

1914 1915 1916
        CoTaskMemFree(alloc_url);
        url = alloc_url = new_url;
        new_url = NULL;
1917
    }
1918

1919
    CoTaskMemFree(new_url);
1920

1921 1922 1923 1924
    if(hres != S_OK) {
        WARN("failed: %08x\n", hres);
        CoTaskMemFree(alloc_url);
        return hres;
1925 1926
    }

1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954
    if(action == PSU_DEFAULT && (protocol_info = get_protocol_info(url))) {
        size = strlenW(url)+1;
        new_url = CoTaskMemAlloc(size * sizeof(WCHAR));
        if(new_url) {
            new_size = 0;
            parse_hres = IInternetProtocolInfo_ParseUrl(protocol_info, url, PARSE_SECURITY_DOMAIN, 0,
                    new_url, size, &new_size, 0);
            if(parse_hres == S_FALSE) {
                if(new_size) {
                    tmp = CoTaskMemRealloc(new_url, new_size*sizeof(WCHAR));
                    if(tmp) {
                        new_url = tmp;
                        parse_hres = IInternetProtocolInfo_ParseUrl(protocol_info, url, PARSE_SECURITY_DOMAIN, 0, new_url,
                                new_size, &new_size, 0);
                        if(parse_hres == S_FALSE)
                            hres = E_FAIL;
                    }else {
                        hres = E_OUTOFMEMORY;
                    }
                }else {
                    hres = E_UNEXPECTED;
                }
            }

            if(hres == S_OK && parse_hres == S_OK) {
                CoTaskMemFree(alloc_url);
                url = alloc_url = new_url;
                new_url = NULL;
1955
            }
1956 1957 1958 1959

            CoTaskMemFree(new_url);
        }else {
            hres = E_OUTOFMEMORY;
1960
        }
1961 1962 1963 1964 1965 1966
        IInternetProtocolInfo_Release(protocol_info);
    }

    if(FAILED(hres)) {
        WARN("failed %08x\n", hres);
        CoTaskMemFree(alloc_url);
1967
        return hres;
1968
    }
1969

1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023
    if(!alloc_url) {
        size = strlenW(url)+1;
        alloc_url = CoTaskMemAlloc(size * sizeof(WCHAR));
        if(!alloc_url)
            return E_OUTOFMEMORY;
        memcpy(alloc_url, url, size * sizeof(WCHAR));
    }

    *result = alloc_url;
    return S_OK;
}

/********************************************************************
 *      CoInternetGetSecurityUrl (URLMON.@)
 */
HRESULT WINAPI CoInternetGetSecurityUrl(LPCWSTR pwzUrl, LPWSTR *ppwzSecUrl, PSUACTION psuAction, DWORD dwReserved)
{
    WCHAR *secure_url;
    HRESULT hres;

    TRACE("(%p,%p,%u,%u)\n", pwzUrl, ppwzSecUrl, psuAction, dwReserved);

    hres = parse_security_url(pwzUrl, psuAction, &secure_url);
    if(FAILED(hres))
        return hres;

    if(psuAction != PSU_SECURITY_URL_ONLY) {
        PARSEDURLW parsed_url = { sizeof(parsed_url) };
        DWORD size;

        /* FIXME: Use helpers from uri.c */
        if(SUCCEEDED(ParseURLW(secure_url, &parsed_url))) {
            WCHAR *new_url;

            switch(parsed_url.nScheme) {
            case URL_SCHEME_FTP:
            case URL_SCHEME_HTTP:
            case URL_SCHEME_HTTPS:
                size = strlenW(secure_url)+1;
                new_url = CoTaskMemAlloc(size * sizeof(WCHAR));
                if(new_url)
                    hres = UrlGetPartW(secure_url, new_url, &size, URL_PART_HOSTNAME, URL_PARTFLAG_KEEPSCHEME);
                else
                    hres = E_OUTOFMEMORY;
                CoTaskMemFree(secure_url);
                if(hres != S_OK) {
                    WARN("UrlGetPart failed: %08x\n", hres);
                    CoTaskMemFree(new_url);
                    return FAILED(hres) ? hres : E_FAIL;
                }
                secure_url = new_url;
            }
        }
    }
2024

2025
    *ppwzSecUrl = secure_url;
2026
    return S_OK;
2027
}
2028 2029 2030 2031 2032 2033

/********************************************************************
 *      CoInternetGetSecurityUrlEx (URLMON.@)
 */
HRESULT WINAPI CoInternetGetSecurityUrlEx(IUri *pUri, IUri **ppSecUri, PSUACTION psuAction, DWORD_PTR dwReserved)
{
2034
    URL_SCHEME scheme_type;
2035 2036 2037
    BSTR secure_uri;
    WCHAR *ret_url;
    HRESULT hres;
2038

2039 2040 2041 2042 2043
    TRACE("(%p,%p,%u,%u)\n", pUri, ppSecUri, psuAction, (DWORD)dwReserved);

    if(!pUri || !ppSecUri)
        return E_INVALIDARG;

2044 2045
    hres = IUri_GetDisplayUri(pUri, &secure_uri);
    if(FAILED(hres))
2046 2047
        return hres;

2048 2049
    hres = parse_security_url(secure_uri, psuAction, &ret_url);
    SysFreeString(secure_uri);
2050 2051 2052 2053
    if(FAILED(hres))
        return hres;

    /* File URIs have to hierarchical. */
2054 2055 2056
    hres = IUri_GetScheme(pUri, (DWORD*)&scheme_type);
    if(SUCCEEDED(hres) && scheme_type == URL_SCHEME_FILE) {
        const WCHAR *tmp = ret_url;
2057 2058 2059

        /* Check and see if a "//" is after the scheme name. */
        tmp += sizeof(fileW)/sizeof(WCHAR);
2060 2061
        if(*tmp != '/' || *(tmp+1) != '/')
            hres = E_INVALIDARG;
2062 2063
    }

2064 2065 2066
    if(SUCCEEDED(hres))
        hres = CreateUri(ret_url, Uri_CREATE_ALLOW_IMPLICIT_WILDCARD_SCHEME, 0, ppSecUri);
    CoTaskMemFree(ret_url);
2067
    return hres;
2068
}
2069 2070 2071 2072 2073 2074 2075 2076 2077

/********************************************************************
 *      CompareSecurityIds (URLMON.@)
 */
HRESULT WINAPI CompareSecurityIds(BYTE *secid1, DWORD size1, BYTE *secid2, DWORD size2, DWORD reserved)
{
    FIXME("(%p %d %p %d %x)\n", secid1, size1, secid2, size2, reserved);
    return E_NOTIMPL;
}