/* * Internet control panel applet: security propsheet * * Copyright 2011 Detlef Riekenberg * * 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 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * */ #define COBJMACROS #define CONST_VTABLE #define NONAMELESSUNION #include <stdarg.h> #include <windef.h> #include <winbase.h> #include <winuser.h> #include <prsht.h> #include "commctrl.h" #include "ole2.h" #include "urlmon.h" #include "initguid.h" #include "winreg.h" #include "shlwapi.h" #include "inetcpl.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(inetcpl); typedef struct secdlg_data_s { HWND hsec; /* security propsheet */ HWND hlv; /* listview */ HWND htb; /* trackbar */ IInternetSecurityManager *sec_mgr; IInternetZoneManager *zone_mgr; DWORD zone_enumerator; DWORD num_zones; ZONEATTRIBUTES *zone_attr; DWORD *zones; DWORD *levels; HIMAGELIST himages; DWORD last_lv_index; DWORD last_level; } secdlg_data; #define NUM_TRACKBAR_POS 5 static DWORD url_templates[] = {URLTEMPLATE_CUSTOM, URLTEMPLATE_LOW, URLTEMPLATE_MEDLOW, URLTEMPLATE_MEDIUM, URLTEMPLATE_MEDHIGH, URLTEMPLATE_HIGH}; /********************************************************************* * index_from_urltemplate [internal] * */ static DWORD index_from_urltemplate(URLTEMPLATE value) { DWORD index = sizeof(url_templates) / sizeof(url_templates[0]); while((index > 0) && (url_templates[index-1] != value)) index--; index--; /* table entries are 0 based */ if (!index && value) FIXME("URLTEMPLATE 0x%x not supported\n", value); TRACE("URLTEMPLATE 0x%08x=> Level %d\n", value, index); return index; } /********************************************************************* * update_security_level [internal] * */ static void update_security_level(secdlg_data *sd, DWORD lv_index, DWORD tb_index) { WCHAR name[512]; DWORD current_index; TRACE("(%p, lv_index: %u, tb_index: %u)\n", sd, lv_index, tb_index); if ((sd->levels[lv_index] != sd->last_level) || (tb_index > 0)) { /* show or hide the trackbar */ if (!sd->levels[lv_index] || !sd->last_level) ShowWindow(sd->htb, sd->levels[lv_index] ? SW_NORMAL : SW_HIDE); current_index = (tb_index > 0) ? tb_index : index_from_urltemplate(sd->levels[lv_index]); name[0] = 0; LoadStringW(hcpl, IDS_SEC_LEVEL0 + current_index, name, sizeof(name)/sizeof(name[0])); TRACE("new level #%d: %s\n", current_index, debugstr_w(name)); SetWindowTextW(GetDlgItem(sd->hsec, IDC_SEC_LEVEL), name); name[0] = 0; LoadStringW(hcpl, IDS_SEC_LEVEL0_INFO + (current_index * 0x10), name, sizeof(name)/sizeof(name[0])); TRACE("new level info: %s\n", debugstr_w(name)); SetWindowTextW(GetDlgItem(sd->hsec, IDC_SEC_LEVEL_INFO), name); if (current_index) SendMessageW(sd->htb, TBM_SETPOS, TRUE, NUM_TRACKBAR_POS - current_index); sd->last_level = sd->levels[lv_index]; } } /********************************************************************* * update_zone_info [internal] * */ static void update_zone_info(secdlg_data *sd, DWORD lv_index) { ZONEATTRIBUTES *za = &sd->zone_attr[lv_index]; WCHAR name[MAX_PATH]; DWORD len; SetWindowTextW(GetDlgItem(sd->hsec, IDC_SEC_ZONE_INFO), za->szDescription); LoadStringW(hcpl, IDS_SEC_SETTINGS, name, sizeof(name)/sizeof(*name)); len = lstrlenW(name); lstrcpynW(&name[len], za->szDisplayName, sizeof(name)/sizeof(*name) - len - 1); TRACE("new title: %s\n", debugstr_w(name)); SetWindowTextW(GetDlgItem(sd->hsec, IDC_SEC_GROUP), name); update_security_level(sd, lv_index, 0); sd->last_lv_index = lv_index; } /********************************************************************* * add_zone_to_listview [internal] * */ static void add_zone_to_listview(secdlg_data *sd, DWORD *pindex, DWORD zone) { DWORD lv_index = *pindex; ZONEATTRIBUTES *za = &sd->zone_attr[lv_index]; LVITEMW lvitem; HRESULT hr; INT iconid = 0; HMODULE hdll = NULL; WCHAR * ptr; HICON icon; TRACE("item %d (zone %d)\n", lv_index, zone); sd->zones[lv_index] = zone; memset(&lvitem, 0, sizeof(LVITEMW)); memset(za, 0, sizeof(ZONEATTRIBUTES)); za->cbSize = sizeof(ZONEATTRIBUTES); hr = IInternetZoneManager_GetZoneAttributes(sd->zone_mgr, zone, za); if (SUCCEEDED(hr)) { TRACE("displayname: %s\n", debugstr_w(za->szDisplayName)); TRACE("description: %s\n", debugstr_w(za->szDescription)); TRACE("minlevel: 0x%x, recommended: 0x%x, current: 0x%x (flags: 0x%x)\n", za->dwTemplateMinLevel, za->dwTemplateRecommended, za->dwTemplateCurrentLevel, za->dwFlags); if (za->dwFlags & ZAFLAGS_NO_UI ) { TRACE("item %d (zone %d): UI disabled for %s\n", lv_index, zone, debugstr_w(za->szDisplayName)); return; } sd->levels[lv_index] = za->dwTemplateCurrentLevel; lvitem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM; lvitem.iItem = lv_index; lvitem.iSubItem = 0; lvitem.pszText = za->szDisplayName; lvitem.lParam = (LPARAM) zone; /* format is "filename.ext#iconid" */ ptr = StrChrW(za->szIconPath, '#'); if (ptr) { *ptr = 0; ptr++; iconid = StrToIntW(ptr); hdll = LoadLibraryExW(za->szIconPath, NULL, LOAD_LIBRARY_AS_DATAFILE); TRACE("%p: icon #%d from %s\n", hdll, iconid, debugstr_w(za->szIconPath)); icon = LoadImageW(hdll, MAKEINTRESOURCEW(iconid), IMAGE_ICON, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), LR_SHARED); if (!icon) { FIXME("item %d (zone %d): missing icon #%d in %s\n", lv_index, zone, iconid, debugstr_w(za->szIconPath)); } /* the failure result (NULL) from LoadImageW let ImageList_AddIcon fail with -1, which is reused in ListView_InsertItemW to disable the image */ lvitem.iImage = ImageList_AddIcon(sd->himages, icon); } else FIXME("item %d (zone %d): malformed szIconPath %s\n", lv_index, zone, debugstr_w(za->szIconPath)); if (ListView_InsertItemW(sd->hlv, &lvitem) >= 0) { /* activate first item in the listview */ if (! lv_index) { lvitem.state = LVIS_FOCUSED | LVIS_SELECTED; lvitem.stateMask = LVIS_FOCUSED | LVIS_SELECTED; SendMessageW(sd->hlv, LVM_SETITEMSTATE, 0, (LPARAM) &lvitem); sd->last_level = ~0; update_zone_info(sd, lv_index); } (*pindex)++; } FreeLibrary(hdll); } else FIXME("item %d (zone %d): GetZoneAttributes failed with 0x%x\n", lv_index, zone, hr); } /********************************************************************* * security_cleanup_zones [internal] * */ static void security_cleanup_zones(secdlg_data *sd) { if (sd->zone_enumerator) { IInternetZoneManager_DestroyZoneEnumerator(sd->zone_mgr, sd->zone_enumerator); } if (sd->zone_mgr) { IInternetZoneManager_Release(sd->zone_mgr); } if (sd->sec_mgr) { IInternetSecurityManager_Release(sd->sec_mgr); } } /********************************************************************* * security_enum_zones [internal] * */ static HRESULT security_enum_zones(secdlg_data * sd) { HRESULT hr; hr = CoInternetCreateSecurityManager(NULL, &sd->sec_mgr, 0); if (SUCCEEDED(hr)) { hr = CoInternetCreateZoneManager(NULL, &sd->zone_mgr, 0); if (SUCCEEDED(hr)) { hr = IInternetZoneManager_CreateZoneEnumerator(sd->zone_mgr, &sd->zone_enumerator, &sd->num_zones, 0); } } return hr; } /********************************************************************* * security_on_destroy [internal] * * handle WM_NCDESTROY * */ static INT_PTR security_on_destroy(secdlg_data * sd) { TRACE("(%p)\n", sd); heap_free(sd->zone_attr); heap_free(sd->zones); if (sd->himages) { SendMessageW(sd->hlv, LVM_SETIMAGELIST, LVSIL_NORMAL, 0); ImageList_Destroy(sd->himages); } security_cleanup_zones(sd); SetWindowLongPtrW(sd->hsec, DWLP_USER, 0); heap_free(sd); return TRUE; } /********************************************************************* * security_on_initdialog [internal] * * handle WM_INITDIALOG * */ static INT_PTR security_on_initdialog(HWND hsec) { secdlg_data *sd; HRESULT hr; DWORD current_zone; DWORD lv_index = 0; DWORD i; sd = heap_alloc_zero(sizeof(secdlg_data)); SetWindowLongPtrW(hsec, DWLP_USER, (LONG_PTR) sd); if (!sd) { return FALSE; } sd->hsec = hsec; sd->hlv = GetDlgItem(hsec, IDC_SEC_LISTVIEW); sd->htb = GetDlgItem(hsec, IDC_SEC_TRACKBAR); EnableWindow(sd->htb, FALSE); /* not changeable yet */ TRACE("(%p) (data: %p, listview: %p, trackbar: %p)\n", hsec, sd, sd->hlv, sd->htb); SendMessageW(sd->htb, TBM_SETRANGE, FALSE, MAKELONG(0, NUM_TRACKBAR_POS - 1)); SendMessageW(sd->htb, TBM_SETTICFREQ, 1, 0 ); /* Create the image lists for the listview */ sd->himages = ImageList_Create(GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), ILC_COLOR32 | ILC_MASK, 1, 1); TRACE("using imagelist: %p\n", sd->himages); if (!sd->himages) { ERR("ImageList_Create failed!\n"); return FALSE; } SendMessageW(sd->hlv, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)sd->himages); hr = security_enum_zones(sd); if (FAILED(hr)) { ERR("got 0x%x\n", hr); security_on_destroy(sd); return FALSE; } TRACE("found %d zones\n", sd->num_zones); /* remember ZONEATTRIBUTES for a listview entry */ sd->zone_attr = heap_alloc(sizeof(ZONEATTRIBUTES) * sd->num_zones); if (!sd->zone_attr) { security_on_destroy(sd); return FALSE; } /* remember zone number and current security level for a listview entry */ sd->zones = heap_alloc((sizeof(DWORD) + sizeof(DWORD)) * sd->num_zones); if (!sd->zones) { security_on_destroy(sd); return FALSE; } sd->levels = &sd->zones[sd->num_zones]; /* use the same order as visible with native inetcpl.cpl */ add_zone_to_listview(sd, &lv_index, URLZONE_INTERNET); add_zone_to_listview(sd, &lv_index, URLZONE_INTRANET); add_zone_to_listview(sd, &lv_index, URLZONE_TRUSTED); add_zone_to_listview(sd, &lv_index, URLZONE_UNTRUSTED); for (i = 0; i < sd->num_zones; i++) { hr = IInternetZoneManager_GetZoneAt(sd->zone_mgr, sd->zone_enumerator, i, ¤t_zone); if (SUCCEEDED(hr) && (current_zone != (DWORD)URLZONE_INVALID)) { if (!current_zone || (current_zone > URLZONE_UNTRUSTED)) { add_zone_to_listview(sd, &lv_index, current_zone); } } } return TRUE; } /********************************************************************* * security_on_notify [internal] * * handle WM_NOTIFY * */ static INT_PTR security_on_notify(secdlg_data *sd, WPARAM wparam, LPARAM lparam) { NMLISTVIEW *nm; nm = (NMLISTVIEW *) lparam; switch (nm->hdr.code) { case LVN_ITEMCHANGED: TRACE("LVN_ITEMCHANGED (0x%lx, 0x%lx) from %p with code: %d (item: %d, uNewState: %u)\n", wparam, lparam, nm->hdr.hwndFrom, nm->hdr.code, nm->iItem, nm->uNewState); if ((nm->uNewState & LVIS_SELECTED) == LVIS_SELECTED) { update_zone_info(sd, nm->iItem); } break; case PSN_APPLY: TRACE("PSN_APPLY (0x%lx, 0x%lx) from %p with code: %d\n", wparam, lparam, nm->hdr.hwndFrom, nm->hdr.code); break; default: TRACE("WM_NOTIFY (0x%lx, 0x%lx) from %p with code: %d\n", wparam, lparam, nm->hdr.hwndFrom, nm->hdr.code); } return FALSE; } /********************************************************************* * security_dlgproc [internal] * */ INT_PTR CALLBACK security_dlgproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { secdlg_data *sd; if (msg == WM_INITDIALOG) { return security_on_initdialog(hwnd); } sd = (secdlg_data *)GetWindowLongPtrW(hwnd, DWLP_USER); if (sd) { switch (msg) { case WM_NOTIFY: return security_on_notify(sd, wparam, lparam); case WM_NCDESTROY: return security_on_destroy(sd); default: /* do not flood the log */ if ((msg == WM_SETCURSOR) || (msg == WM_NCHITTEST) || (msg == WM_MOUSEMOVE) || (msg == WM_MOUSEACTIVATE) || (msg == WM_PARENTNOTIFY)) return FALSE; TRACE("(%p, 0x%08x/%03d, 0x%08lx, 0x%08lx)\n", hwnd, msg, msg, wparam, lparam); } } return FALSE; }