Synchronize with trunk revision 59636 (just before Alex's CreateProcess revamp).
[reactos.git] / dll / cpl / inetcpl / security.c
1 /*
2 * Internet control panel applet: security propsheet
3 *
4 * Copyright 2011 Detlef Riekenberg
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 *
20 */
21
22 #define COBJMACROS
23 #define CONST_VTABLE
24 #define NONAMELESSUNION
25
26 #define WIN32_NO_STATUS
27 #define _INC_WINDOWS
28 #define COM_NO_WINDOWS_H
29
30 #include <stdarg.h>
31 #include <windef.h>
32 #include <winbase.h>
33 #include <winuser.h>
34 //#include <prsht.h>
35 //#include "commctrl.h"
36
37 //#include "ole2.h"
38 //#include "urlmon.h"
39 //#include "initguid.h"
40 #include <winreg.h>
41 #include <shlwapi.h>
42
43 #include "inetcpl.h"
44 #include <wine/debug.h>
45
46 WINE_DEFAULT_DEBUG_CHANNEL(inetcpl);
47
48 typedef struct secdlg_data_s {
49 HWND hsec; /* security propsheet */
50 HWND hlv; /* listview */
51 HWND htb; /* trackbar */
52 IInternetSecurityManager *sec_mgr;
53 IInternetZoneManager *zone_mgr;
54 DWORD zone_enumerator;
55 DWORD num_zones;
56 ZONEATTRIBUTES *zone_attr;
57 DWORD *zones;
58 DWORD *levels;
59 HIMAGELIST himages;
60 DWORD last_lv_index;
61 DWORD last_level;
62 } secdlg_data;
63
64 #define NUM_TRACKBAR_POS 5
65
66 static WCHAR spaceW[] = {' ',0};
67 static DWORD url_templates[] = {URLTEMPLATE_CUSTOM,
68 URLTEMPLATE_LOW,
69 URLTEMPLATE_MEDLOW,
70 URLTEMPLATE_MEDIUM,
71 URLTEMPLATE_MEDHIGH,
72 URLTEMPLATE_HIGH};
73
74 /*********************************************************************
75 * index_from_urltemplate [internal]
76 *
77 */
78 static DWORD index_from_urltemplate(URLTEMPLATE value)
79 {
80
81 DWORD index = sizeof(url_templates) / sizeof(url_templates[0]);
82
83 while((index > 0) && (url_templates[index-1] != value))
84 index--;
85
86 index--; /* table entries are 0 based */
87 if (!index && value)
88 FIXME("URLTEMPLATE 0x%x not supported\n", value);
89
90 TRACE("URLTEMPLATE 0x%08x=> Level %d\n", value, index);
91 return index;
92 }
93
94 /*********************************************************************
95 * update_security_level [internal]
96 *
97 */
98 static void update_security_level(secdlg_data *sd, DWORD lv_index, DWORD tb_index)
99 {
100 WCHAR name[512];
101 DWORD current_index;
102
103 TRACE("(%p, lv_index: %u, tb_index: %u)\n", sd, lv_index, tb_index);
104
105 if ((sd->levels[lv_index] != sd->last_level) || (tb_index > 0)) {
106 /* show or hide the trackbar */
107 if (!sd->levels[lv_index] || !sd->last_level)
108 ShowWindow(sd->htb, sd->levels[lv_index] ? SW_NORMAL : SW_HIDE);
109
110 current_index = (tb_index > 0) ? tb_index : index_from_urltemplate(sd->levels[lv_index]);
111
112 name[0] = 0;
113 LoadStringW(hcpl, IDS_SEC_LEVEL0 + current_index, name, sizeof(name)/sizeof(name[0]));
114 TRACE("new level #%d: %s\n", current_index, debugstr_w(name));
115 SetWindowTextW(GetDlgItem(sd->hsec, IDC_SEC_LEVEL), name);
116
117 name[0] = 0;
118 LoadStringW(hcpl, IDS_SEC_LEVEL0_INFO + (current_index * 0x10), name, sizeof(name)/sizeof(name[0]));
119 TRACE("new level info: %s\n", debugstr_w(name));
120 SetWindowTextW(GetDlgItem(sd->hsec, IDC_SEC_LEVEL_INFO), name);
121
122 if (current_index)
123 SendMessageW(sd->htb, TBM_SETPOS, TRUE, NUM_TRACKBAR_POS - current_index);
124
125 sd->last_level = sd->levels[lv_index];
126
127 }
128 }
129
130 /*********************************************************************
131 * update_zone_info [internal]
132 *
133 */
134 static void update_zone_info(secdlg_data *sd, DWORD lv_index)
135 {
136 ZONEATTRIBUTES *za = &sd->zone_attr[lv_index];
137 WCHAR name[MAX_PATH];
138 DWORD len;
139
140 SetWindowTextW(GetDlgItem(sd->hsec, IDC_SEC_ZONE_INFO), za->szDescription);
141
142 name[0] = ' ';
143 name[1] = 0;
144
145 LoadStringW(hcpl, IDS_SEC_SETTINGS, &name[1], sizeof(name)/sizeof(name[0]) - 3);
146 len = lstrlenW(name);
147 lstrcpynW(&name[len], za->szDisplayName, sizeof(name)/sizeof(name[0]) - len - 3);
148 lstrcatW(name, spaceW);
149
150 TRACE("new title: %s\n", debugstr_w(name));
151 SetWindowTextW(GetDlgItem(sd->hsec, IDC_SEC_GROUP), name);
152
153 update_security_level(sd, lv_index, 0);
154 sd->last_lv_index = lv_index;
155 }
156
157 /*********************************************************************
158 * add_zone_to_listview [internal]
159 *
160 */
161 static void add_zone_to_listview(secdlg_data *sd, DWORD *pindex, DWORD zone)
162 {
163 DWORD lv_index = *pindex;
164 ZONEATTRIBUTES *za = &sd->zone_attr[lv_index];
165 LVITEMW lvitem;
166 HRESULT hr;
167 INT iconid = 0;
168 HMODULE hdll = NULL;
169 WCHAR * ptr;
170 HICON icon;
171
172 TRACE("item %d (zone %d)\n", lv_index, zone);
173
174 sd->zones[lv_index] = zone;
175
176 memset(&lvitem, 0, sizeof(LVITEMW));
177 memset(za, 0, sizeof(ZONEATTRIBUTES));
178 za->cbSize = sizeof(ZONEATTRIBUTES);
179 hr = IInternetZoneManager_GetZoneAttributes(sd->zone_mgr, zone, za);
180 if (SUCCEEDED(hr)) {
181 TRACE("displayname: %s\n", debugstr_w(za->szDisplayName));
182 TRACE("description: %s\n", debugstr_w(za->szDescription));
183 TRACE("minlevel: 0x%x, recommended: 0x%x, current: 0x%x (flags: 0x%x)\n", za->dwTemplateMinLevel,
184 za->dwTemplateRecommended, za->dwTemplateCurrentLevel, za->dwFlags);
185
186 if (za->dwFlags & ZAFLAGS_NO_UI ) {
187 TRACE("item %d (zone %d): UI disabled for %s\n", lv_index, zone, debugstr_w(za->szDisplayName));
188 return;
189 }
190
191 sd->levels[lv_index] = za->dwTemplateCurrentLevel;
192
193 lvitem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM;
194 lvitem.iItem = lv_index;
195 lvitem.iSubItem = 0;
196 lvitem.pszText = za->szDisplayName;
197 lvitem.lParam = (LPARAM) zone;
198
199 /* format is "filename.ext#iconid" */
200 ptr = StrChrW(za->szIconPath, '#');
201 if (ptr) {
202 *ptr = 0;
203 ptr++;
204 iconid = StrToIntW(ptr);
205 hdll = LoadLibraryExW(za->szIconPath, NULL, LOAD_LIBRARY_AS_DATAFILE);
206 TRACE("%p: icon #%d from %s\n", hdll, iconid, debugstr_w(za->szIconPath));
207
208 icon = LoadImageW(hdll, MAKEINTRESOURCEW(iconid), IMAGE_ICON, GetSystemMetrics(SM_CXICON),
209 GetSystemMetrics(SM_CYICON), LR_SHARED);
210
211 if (!icon) {
212 FIXME("item %d (zone %d): missing icon #%d in %s\n", lv_index, zone, iconid, debugstr_w(za->szIconPath));
213 }
214
215 /* the failure result (NULL) from LoadImageW let ImageList_AddIcon fail
216 with -1, which is reused in ListView_InsertItemW to disable the image */
217 lvitem.iImage = ImageList_AddIcon(sd->himages, icon);
218 }
219 else
220 FIXME("item %d (zone %d): malformed szIconPath %s\n", lv_index, zone, debugstr_w(za->szIconPath));
221
222 if (ListView_InsertItemW(sd->hlv, &lvitem) >= 0) {
223 /* activate first item in the listview */
224 if (! lv_index) {
225 lvitem.state = LVIS_FOCUSED | LVIS_SELECTED;
226 lvitem.stateMask = LVIS_FOCUSED | LVIS_SELECTED;
227 SendMessageW(sd->hlv, LVM_SETITEMSTATE, 0, (LPARAM) &lvitem);
228 sd->last_level = ~0;
229 update_zone_info(sd, lv_index);
230 }
231 (*pindex)++;
232 }
233 FreeLibrary(hdll);
234 }
235 else
236 FIXME("item %d (zone %d): GetZoneAttributes failed with 0x%x\n", lv_index, zone, hr);
237 }
238
239 /*********************************************************************
240 * security_cleanup_zones [internal]
241 *
242 */
243 static void security_cleanup_zones(secdlg_data *sd)
244 {
245 if (sd->zone_enumerator) {
246 IInternetZoneManager_DestroyZoneEnumerator(sd->zone_mgr, sd->zone_enumerator);
247 }
248
249 if (sd->zone_mgr) {
250 IInternetZoneManager_Release(sd->zone_mgr);
251 }
252
253 if (sd->sec_mgr) {
254 IInternetSecurityManager_Release(sd->sec_mgr);
255 }
256 }
257
258 /*********************************************************************
259 * security_enum_zones [internal]
260 *
261 */
262 static HRESULT security_enum_zones(secdlg_data * sd)
263 {
264 HRESULT hr;
265
266 hr = CoInternetCreateSecurityManager(NULL, &sd->sec_mgr, 0);
267 if (SUCCEEDED(hr)) {
268 hr = CoInternetCreateZoneManager(NULL, &sd->zone_mgr, 0);
269 if (SUCCEEDED(hr)) {
270 hr = IInternetZoneManager_CreateZoneEnumerator(sd->zone_mgr, &sd->zone_enumerator, &sd->num_zones, 0);
271 }
272 }
273 return hr;
274 }
275
276 /*********************************************************************
277 * security_on_destroy [internal]
278 *
279 * handle WM_NCDESTROY
280 *
281 */
282 static INT_PTR security_on_destroy(secdlg_data * sd)
283 {
284 TRACE("(%p)\n", sd);
285
286 heap_free(sd->zone_attr);
287 heap_free(sd->zones);
288 if (sd->himages) {
289 SendMessageW(sd->hlv, LVM_SETIMAGELIST, LVSIL_NORMAL, 0);
290 ImageList_Destroy(sd->himages);
291 }
292
293 security_cleanup_zones(sd);
294 SetWindowLongPtrW(sd->hsec, DWLP_USER, 0);
295 heap_free(sd);
296 return TRUE;
297 }
298
299 /*********************************************************************
300 * security_on_initdialog [internal]
301 *
302 * handle WM_INITDIALOG
303 *
304 */
305 static INT_PTR security_on_initdialog(HWND hsec)
306 {
307 secdlg_data *sd;
308 HRESULT hr;
309 DWORD current_zone;
310 DWORD lv_index = 0;
311 DWORD i;
312
313 sd = heap_alloc_zero(sizeof(secdlg_data));
314 SetWindowLongPtrW(hsec, DWLP_USER, (LONG_PTR) sd);
315 if (!sd) {
316 return FALSE;
317 }
318
319 sd->hsec = hsec;
320 sd->hlv = GetDlgItem(hsec, IDC_SEC_LISTVIEW);
321 sd->htb = GetDlgItem(hsec, IDC_SEC_TRACKBAR);
322
323 EnableWindow(sd->htb, FALSE); /* not changeable yet */
324
325 TRACE("(%p) (data: %p, listview: %p, trackbar: %p)\n", hsec, sd, sd->hlv, sd->htb);
326
327 SendMessageW(sd->htb, TBM_SETRANGE, FALSE, MAKELONG(0, NUM_TRACKBAR_POS - 1));
328 SendMessageW(sd->htb, TBM_SETTICFREQ, 1, 0 );
329
330 /* Create the image lists for the listview */
331 sd->himages = ImageList_Create(GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), ILC_COLOR32 | ILC_MASK, 1, 1);
332
333 TRACE("using imagelist: %p\n", sd->himages);
334 if (!sd->himages) {
335 ERR("ImageList_Create failed!\n");
336 return FALSE;
337 }
338 SendMessageW(sd->hlv, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)sd->himages);
339
340 hr = security_enum_zones(sd);
341 if (FAILED(hr)) {
342 ERR("got 0x%x\n", hr);
343 security_on_destroy(sd);
344 return FALSE;
345 }
346
347 TRACE("found %d zones\n", sd->num_zones);
348
349 /* remember ZONEATTRIBUTES for a listview entry */
350 sd->zone_attr = heap_alloc(sizeof(ZONEATTRIBUTES) * sd->num_zones);
351 if (!sd->zone_attr) {
352 security_on_destroy(sd);
353 return FALSE;
354 }
355
356 /* remember zone number and current security level for a listview entry */
357 sd->zones = heap_alloc((sizeof(DWORD) + sizeof(DWORD)) * sd->num_zones);
358 if (!sd->zones) {
359 security_on_destroy(sd);
360 return FALSE;
361 }
362 sd->levels = &sd->zones[sd->num_zones];
363
364 /* use the same order as visible with native inetcpl.cpl */
365 add_zone_to_listview(sd, &lv_index, URLZONE_INTERNET);
366 add_zone_to_listview(sd, &lv_index, URLZONE_INTRANET);
367 add_zone_to_listview(sd, &lv_index, URLZONE_TRUSTED);
368 add_zone_to_listview(sd, &lv_index, URLZONE_UNTRUSTED);
369
370 for (i = 0; i < sd->num_zones; i++)
371 {
372 hr = IInternetZoneManager_GetZoneAt(sd->zone_mgr, sd->zone_enumerator, i, &current_zone);
373 if (SUCCEEDED(hr) && (current_zone != (DWORD)URLZONE_INVALID)) {
374 if (!current_zone || (current_zone > URLZONE_UNTRUSTED)) {
375 add_zone_to_listview(sd, &lv_index, current_zone);
376 }
377 }
378 }
379 return TRUE;
380 }
381
382 /*********************************************************************
383 * security_on_notify [internal]
384 *
385 * handle WM_NOTIFY
386 *
387 */
388 static INT_PTR security_on_notify(secdlg_data *sd, WPARAM wparam, LPARAM lparam)
389 {
390 NMLISTVIEW *nm;
391
392 nm = (NMLISTVIEW *) lparam;
393 switch (nm->hdr.code)
394 {
395 case LVN_ITEMCHANGED:
396 TRACE("LVN_ITEMCHANGED (0x%lx, 0x%lx) from %p with code: %d (item: %d, uNewState: %u)\n",
397 wparam, lparam, nm->hdr.hwndFrom, nm->hdr.code, nm->iItem, nm->uNewState);
398 if ((nm->uNewState & LVIS_SELECTED) == LVIS_SELECTED) {
399 update_zone_info(sd, nm->iItem);
400 }
401 break;
402
403 case PSN_APPLY:
404 TRACE("PSN_APPLY (0x%lx, 0x%lx) from %p with code: %d\n", wparam, lparam,
405 nm->hdr.hwndFrom, nm->hdr.code);
406 break;
407
408 default:
409 TRACE("WM_NOTIFY (0x%lx, 0x%lx) from %p with code: %d\n", wparam, lparam,
410 nm->hdr.hwndFrom, nm->hdr.code);
411
412 }
413 return FALSE;
414 }
415
416 /*********************************************************************
417 * security_dlgproc [internal]
418 *
419 */
420 INT_PTR CALLBACK security_dlgproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
421 {
422 secdlg_data *sd;
423
424 if (msg == WM_INITDIALOG) {
425 return security_on_initdialog(hwnd);
426 }
427
428 sd = (secdlg_data *)GetWindowLongPtrW(hwnd, DWLP_USER);
429 if (sd) {
430 switch (msg)
431 {
432 case WM_NOTIFY:
433 return security_on_notify(sd, wparam, lparam);
434
435 case WM_NCDESTROY:
436 return security_on_destroy(sd);
437
438 default:
439 /* do not flood the log */
440 if ((msg == WM_SETCURSOR) || (msg == WM_NCHITTEST) ||
441 (msg == WM_MOUSEMOVE) || (msg == WM_MOUSEACTIVATE) || (msg == WM_PARENTNOTIFY))
442 return FALSE;
443
444 TRACE("(%p, 0x%08x/%03d, 0x%08lx, 0x%08lx)\n", hwnd, msg, msg, wparam, lparam);
445 }
446 }
447 return FALSE;
448 }