ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

main.c
Go to the documentation of this file.
00001 /*
00002  * Copyright 2008 Juan Lang
00003  *
00004  * This library is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU Lesser General Public
00006  * License as published by the Free Software Foundation; either
00007  * version 2.1 of the License, or (at your option) any later version.
00008  *
00009  * This library is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * Lesser General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU Lesser General Public
00015  * License along with this library; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00017  */
00018 
00019 #include "config.h"
00020 
00021 #include <stdarg.h>
00022 
00023 #define COBJMACROS
00024 #define NONAMELESSUNION
00025 
00026 #include "windef.h"
00027 #include "winbase.h"
00028 #include "winnls.h"
00029 #include "winuser.h"
00030 #include "softpub.h"
00031 #include "wingdi.h"
00032 #include "richedit.h"
00033 #include "ole2.h"
00034 #include "richole.h"
00035 #include "commdlg.h"
00036 #include "commctrl.h"
00037 #include "cryptuiapi.h"
00038 #include "cryptuires.h"
00039 #include "urlmon.h"
00040 #include "hlink.h"
00041 #include "winreg.h"
00042 #include "wine/debug.h"
00043 #include "wine/unicode.h"
00044 
00045 WINE_DEFAULT_DEBUG_CHANNEL(cryptui);
00046 
00047 static HINSTANCE hInstance;
00048 
00049 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
00050 {
00051     TRACE("(0x%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
00052 
00053     switch (fdwReason)
00054     {
00055         case DLL_WINE_PREATTACH:
00056             return FALSE;    /* prefer native version */
00057         case DLL_PROCESS_ATTACH:
00058             hInstance = hinstDLL;
00059             DisableThreadLibraryCalls(hinstDLL);
00060             break;
00061         case DLL_PROCESS_DETACH:
00062             break;
00063         default:
00064             break;
00065     }
00066     return TRUE;
00067 }
00068 
00069 #define MAX_STRING_LEN 512
00070 
00071 static void add_cert_columns(HWND hwnd)
00072 {
00073     HWND lv = GetDlgItem(hwnd, IDC_MGR_CERTS);
00074     RECT rc;
00075     WCHAR buf[MAX_STRING_LEN];
00076     LVCOLUMNW column;
00077 
00078     SendMessageW(lv, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
00079     GetWindowRect(lv, &rc);
00080     LoadStringW(hInstance, IDS_SUBJECT_COLUMN, buf,
00081      sizeof(buf) / sizeof(buf[0]));
00082     column.mask = LVCF_WIDTH | LVCF_TEXT;
00083     column.cx = (rc.right - rc.left) * 29 / 100 - 2;
00084     column.pszText = buf;
00085     SendMessageW(lv, LVM_INSERTCOLUMNW, 0, (LPARAM)&column);
00086     LoadStringW(hInstance, IDS_ISSUER_COLUMN, buf,
00087      sizeof(buf) / sizeof(buf[0]));
00088     SendMessageW(lv, LVM_INSERTCOLUMNW, 1, (LPARAM)&column);
00089     column.cx = (rc.right - rc.left) * 16 / 100 - 2;
00090     LoadStringW(hInstance, IDS_EXPIRATION_COLUMN, buf,
00091      sizeof(buf) / sizeof(buf[0]));
00092     SendMessageW(lv, LVM_INSERTCOLUMNW, 2, (LPARAM)&column);
00093     column.cx = (rc.right - rc.left) * 23 / 100 - 1;
00094     LoadStringW(hInstance, IDS_FRIENDLY_NAME_COLUMN, buf,
00095      sizeof(buf) / sizeof(buf[0]));
00096     SendMessageW(lv, LVM_INSERTCOLUMNW, 3, (LPARAM)&column);
00097 }
00098 
00099 static void add_cert_to_view(HWND lv, PCCERT_CONTEXT cert, DWORD *allocatedLen,
00100  LPWSTR *str)
00101 {
00102     DWORD len;
00103     LVITEMW item;
00104     WCHAR dateFmt[80]; /* sufficient for LOCALE_SSHORTDATE */
00105     WCHAR date[80];
00106     SYSTEMTIME sysTime;
00107     LPWSTR none;
00108 
00109     item.mask = LVIF_IMAGE | LVIF_PARAM | LVIF_TEXT;
00110     item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
00111     item.iSubItem = 0;
00112     item.iImage = 0;
00113     item.lParam = (LPARAM)CertDuplicateCertificateContext(cert);
00114     len = CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL,
00115      NULL, 0);
00116     if (len > *allocatedLen)
00117     {
00118         HeapFree(GetProcessHeap(), 0, *str);
00119         *str = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
00120         if (*str)
00121             *allocatedLen = len;
00122     }
00123     if (*str)
00124     {
00125         CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL,
00126          *str, len);
00127         item.pszText = *str;
00128         SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
00129     }
00130 
00131     item.mask = LVIF_TEXT;
00132     len = CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE,
00133      CERT_NAME_ISSUER_FLAG, NULL, NULL, 0);
00134     if (len > *allocatedLen)
00135     {
00136         HeapFree(GetProcessHeap(), 0, *str);
00137         *str = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
00138         if (*str)
00139             *allocatedLen = len;
00140     }
00141     if (*str)
00142     {
00143         CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE,
00144          CERT_NAME_ISSUER_FLAG, NULL, *str, len);
00145         item.pszText = *str;
00146         item.iSubItem = 1;
00147         SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
00148     }
00149 
00150     GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT, LOCALE_SSHORTDATE, dateFmt,
00151      sizeof(dateFmt) / sizeof(dateFmt[0]));
00152     FileTimeToSystemTime(&cert->pCertInfo->NotAfter, &sysTime);
00153     GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, date,
00154      sizeof(date) / sizeof(date[0]));
00155     item.pszText = date;
00156     item.iSubItem = 2;
00157     SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
00158 
00159     if (!CertGetCertificateContextProperty(cert, CERT_FRIENDLY_NAME_PROP_ID,
00160      NULL, &len))
00161         len = LoadStringW(hInstance, IDS_FRIENDLY_NAME_NONE, (LPWSTR)&none, 0);
00162     if (len > *allocatedLen)
00163     {
00164         HeapFree(GetProcessHeap(), 0, *str);
00165         *str = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
00166         if (*str)
00167             *allocatedLen = len;
00168     }
00169     if (*str)
00170     {
00171         if (!CertGetCertificateContextProperty(cert, CERT_FRIENDLY_NAME_PROP_ID,
00172          *str, &len))
00173             item.pszText = none;
00174         else
00175             item.pszText = *str;
00176         item.iSubItem = 3;
00177         SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
00178     }
00179 }
00180 
00181 static LPSTR get_cert_mgr_usages(void)
00182 {
00183     static const WCHAR keyName[] = { 'S','o','f','t','w','a','r','e','\\','M',
00184      'i','c','r','o','s','o','f','t','\\','C','r','y','p','t','o','g','r','a',
00185      'p','h','y','\\','U','I','\\','C','e','r','t','m','g','r','\\','P','u',
00186      'r','p','o','s','e',0 };
00187     LPSTR str = NULL;
00188     HKEY key;
00189 
00190     if (!RegCreateKeyExW(HKEY_CURRENT_USER, keyName, 0, NULL, 0, KEY_READ,
00191      NULL, &key, NULL))
00192     {
00193         LONG rc;
00194         DWORD type, size;
00195 
00196         rc = RegQueryValueExA(key, "Purpose", NULL, &type, NULL, &size);
00197         if ((!rc || rc == ERROR_MORE_DATA) && type == REG_SZ)
00198         {
00199             str = HeapAlloc(GetProcessHeap(), 0, size);
00200             if (str)
00201             {
00202                 rc = RegQueryValueExA(key, "Purpose", NULL, NULL, (LPBYTE)str,
00203                  &size);
00204                 if (rc)
00205                 {
00206                     HeapFree(GetProcessHeap(), 0, str);
00207                     str = NULL;
00208                 }
00209             }
00210         }
00211         RegCloseKey(key);
00212     }
00213     return str;
00214 }
00215 
00216 typedef enum {
00217     PurposeFilterShowAll = 0,
00218     PurposeFilterShowAdvanced = 1,
00219     PurposeFilterShowOID = 2
00220 } PurposeFilter;
00221 
00222 static void initialize_purpose_selection(HWND hwnd)
00223 {
00224     HWND cb = GetDlgItem(hwnd, IDC_MGR_PURPOSE_SELECTION);
00225     WCHAR buf[MAX_STRING_LEN];
00226     LPSTR usages;
00227     int index;
00228 
00229     LoadStringW(hInstance, IDS_PURPOSE_ALL, buf,
00230      sizeof(buf) / sizeof(buf[0]));
00231     index = SendMessageW(cb, CB_INSERTSTRING, -1, (LPARAM)buf);
00232     SendMessageW(cb, CB_SETITEMDATA, index, (LPARAM)PurposeFilterShowAll);
00233     LoadStringW(hInstance, IDS_PURPOSE_ADVANCED, buf,
00234      sizeof(buf) / sizeof(buf[0]));
00235     index = SendMessageW(cb, CB_INSERTSTRING, -1, (LPARAM)buf);
00236     SendMessageW(cb, CB_SETITEMDATA, index, (LPARAM)PurposeFilterShowAdvanced);
00237     SendMessageW(cb, CB_SETCURSEL, 0, 0);
00238     if ((usages = get_cert_mgr_usages()))
00239     {
00240         LPSTR ptr, comma;
00241 
00242         for (ptr = usages, comma = strchr(ptr, ','); ptr && *ptr;
00243          ptr = comma ? comma + 1 : NULL,
00244          comma = ptr ? strchr(ptr, ',') : NULL)
00245         {
00246             PCCRYPT_OID_INFO info;
00247 
00248             if (comma)
00249                 *comma = 0;
00250             if ((info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, ptr, 0)))
00251             {
00252                 index = SendMessageW(cb, CB_INSERTSTRING, 0,
00253                  (LPARAM)info->pwszName);
00254                 SendMessageW(cb, CB_SETITEMDATA, index, (LPARAM)info);
00255             }
00256         }
00257         HeapFree(GetProcessHeap(), 0, usages);
00258     }
00259 }
00260 
00261 extern BOOL WINAPI WTHelperGetKnownUsages(DWORD action,
00262  PCCRYPT_OID_INFO **usages);
00263 
00264 static CERT_ENHKEY_USAGE *add_oid_to_usage(CERT_ENHKEY_USAGE *usage, LPSTR oid)
00265 {
00266     if (!usage->cUsageIdentifier)
00267         usage->rgpszUsageIdentifier = HeapAlloc(GetProcessHeap(), 0,
00268          sizeof(LPSTR));
00269     else
00270         usage->rgpszUsageIdentifier = HeapReAlloc(GetProcessHeap(), 0,
00271          usage->rgpszUsageIdentifier,
00272          (usage->cUsageIdentifier + 1) * sizeof(LPSTR));
00273     if (usage->rgpszUsageIdentifier)
00274         usage->rgpszUsageIdentifier[usage->cUsageIdentifier++] = oid;
00275     else
00276     {
00277         HeapFree(GetProcessHeap(), 0, usage);
00278         usage = NULL;
00279     }
00280     return usage;
00281 }
00282 
00283 static CERT_ENHKEY_USAGE *convert_usages_str_to_usage(LPSTR usageStr)
00284 {
00285     CERT_ENHKEY_USAGE *usage = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
00286      sizeof(CERT_ENHKEY_USAGE));
00287 
00288     if (usage)
00289     {
00290         LPSTR ptr, comma;
00291 
00292         for (ptr = usageStr, comma = strchr(ptr, ','); usage && ptr && *ptr;
00293          ptr = comma ? comma + 1 : NULL,
00294          comma = ptr ? strchr(ptr, ',') : NULL)
00295         {
00296             if (comma)
00297                 *comma = 0;
00298             add_oid_to_usage(usage, ptr);
00299         }
00300     }
00301     return usage;
00302 }
00303 
00304 static CERT_ENHKEY_USAGE *create_advanced_filter(void)
00305 {
00306     CERT_ENHKEY_USAGE *advancedUsage = HeapAlloc(GetProcessHeap(),
00307      HEAP_ZERO_MEMORY, sizeof(CERT_ENHKEY_USAGE));
00308 
00309     if (advancedUsage)
00310     {
00311         PCCRYPT_OID_INFO *usages;
00312 
00313         if (WTHelperGetKnownUsages(1, &usages))
00314         {
00315             LPSTR disabledUsagesStr;
00316 
00317             if ((disabledUsagesStr = get_cert_mgr_usages()))
00318             {
00319                 CERT_ENHKEY_USAGE *disabledUsages =
00320                  convert_usages_str_to_usage(disabledUsagesStr);
00321 
00322                 if (disabledUsages)
00323                 {
00324                     PCCRYPT_OID_INFO *ptr;
00325 
00326                     for (ptr = usages; *ptr; ptr++)
00327                     {
00328                         DWORD i;
00329                         BOOL disabled = FALSE;
00330 
00331                         for (i = 0; !disabled &&
00332                          i < disabledUsages->cUsageIdentifier; i++)
00333                             if (!strcmp(disabledUsages->rgpszUsageIdentifier[i],
00334                              (*ptr)->pszOID))
00335                                 disabled = TRUE;
00336                         if (!disabled)
00337                             add_oid_to_usage(advancedUsage,
00338                              (LPSTR)(*ptr)->pszOID);
00339                     }
00340                     /* The individual strings are pointers to disabledUsagesStr,
00341                      * so they're freed when it is.
00342                      */
00343                     HeapFree(GetProcessHeap(), 0,
00344                      disabledUsages->rgpszUsageIdentifier);
00345                     HeapFree(GetProcessHeap(), 0, disabledUsages);
00346                 }
00347                 HeapFree(GetProcessHeap(), 0, disabledUsagesStr);
00348             }
00349             WTHelperGetKnownUsages(2, &usages);
00350         }
00351     }
00352     return advancedUsage;
00353 }
00354 
00355 static int CALLBACK cert_mgr_sort_by_subject(LPARAM lp1, LPARAM lp2, LPARAM lp);
00356 
00357 static void show_store_certs(HWND hwnd, HCERTSTORE store)
00358 {
00359     HWND lv = GetDlgItem(hwnd, IDC_MGR_CERTS);
00360     HWND cb = GetDlgItem(hwnd, IDC_MGR_PURPOSE_SELECTION);
00361     PCCERT_CONTEXT cert = NULL;
00362     DWORD allocatedLen = 0;
00363     LPWSTR str = NULL;
00364     int index;
00365     PurposeFilter filter = PurposeFilterShowAll;
00366     LPCSTR oid = NULL;
00367     CERT_ENHKEY_USAGE *advanced = NULL;
00368 
00369     index = SendMessageW(cb, CB_GETCURSEL, 0, 0);
00370     if (index >= 0)
00371     {
00372         INT_PTR data = SendMessageW(cb, CB_GETITEMDATA, index, 0);
00373 
00374         if (!HIWORD(data))
00375             filter = data;
00376         else
00377         {
00378             PCCRYPT_OID_INFO info = (PCCRYPT_OID_INFO)data;
00379 
00380             filter = PurposeFilterShowOID;
00381             oid = info->pszOID;
00382         }
00383     }
00384     if (filter == PurposeFilterShowAdvanced)
00385         advanced = create_advanced_filter();
00386     do {
00387         cert = CertEnumCertificatesInStore(store, cert);
00388         if (cert)
00389         {
00390             BOOL show = FALSE;
00391 
00392             if (filter == PurposeFilterShowAll)
00393                 show = TRUE;
00394             else
00395             {
00396                 int numOIDs;
00397                 DWORD cbOIDs = 0;
00398 
00399                 if (CertGetValidUsages(1, &cert, &numOIDs, NULL, &cbOIDs))
00400                 {
00401                     if (numOIDs == -1)
00402                     {
00403                         /* -1 implies all usages are valid */
00404                         show = TRUE;
00405                     }
00406                     else
00407                     {
00408                         LPSTR *oids = HeapAlloc(GetProcessHeap(), 0, cbOIDs);
00409 
00410                         if (oids)
00411                         {
00412                             if (CertGetValidUsages(1, &cert, &numOIDs, oids,
00413                              &cbOIDs))
00414                             {
00415                                 int i;
00416 
00417                                 if (filter == PurposeFilterShowOID)
00418                                 {
00419                                     for (i = 0; !show && i < numOIDs; i++)
00420                                         if (!strcmp(oids[i], oid))
00421                                             show = TRUE;
00422                                 }
00423                                 else
00424                                 {
00425                                     for (i = 0; !show && i < numOIDs; i++)
00426                                     {
00427                                         DWORD j;
00428 
00429                                         for (j = 0; !show &&
00430                                          j < advanced->cUsageIdentifier; j++)
00431                                             if (!strcmp(oids[i],
00432                                              advanced->rgpszUsageIdentifier[j]))
00433                                                 show = TRUE;
00434                                     }
00435                                 }
00436                             }
00437                             HeapFree(GetProcessHeap(), 0, oids);
00438                         }
00439                     }
00440                 }
00441             }
00442             if (show)
00443                 add_cert_to_view(lv, cert, &allocatedLen, &str);
00444         }
00445     } while (cert);
00446     HeapFree(GetProcessHeap(), 0, str);
00447     if (advanced)
00448     {
00449         HeapFree(GetProcessHeap(), 0, advanced->rgpszUsageIdentifier);
00450         HeapFree(GetProcessHeap(), 0, advanced);
00451     }
00452     SendMessageW(lv, LVM_SORTITEMSEX, (WPARAM)lv,
00453      (LPARAM)cert_mgr_sort_by_subject);
00454 }
00455 
00456 static const WCHAR my[] = { 'M','y',0 };
00457 static const WCHAR addressBook[] = {
00458  'A','d','d','r','e','s','s','B','o','o','k',0 };
00459 static const WCHAR ca[] = { 'C','A',0 };
00460 static const WCHAR root[] = { 'R','o','o','t',0 };
00461 static const WCHAR trustedPublisher[] = {
00462  'T','r','u','s','t','e','d','P','u','b','l','i','s','h','e','r',0 };
00463 static const WCHAR disallowed[] = { 'D','i','s','a','l','l','o','w','e','d',0 };
00464 
00465 struct CertMgrStoreInfo
00466 {
00467     LPCWSTR name;
00468     int removeWarning;
00469     int removePluralWarning;
00470 };
00471 
00472 static const struct CertMgrStoreInfo defaultStoreList[] = {
00473  { my, IDS_WARN_REMOVE_MY, IDS_WARN_REMOVE_PLURAL_MY },
00474  { addressBook, IDS_WARN_REMOVE_ADDRESSBOOK,
00475    IDS_WARN_REMOVE_PLURAL_ADDRESSBOOK },
00476  { ca, IDS_WARN_REMOVE_CA, IDS_WARN_REMOVE_PLURAL_CA },
00477  { root, IDS_WARN_REMOVE_ROOT, IDS_WARN_REMOVE_PLURAL_ROOT },
00478  { trustedPublisher, IDS_WARN_REMOVE_TRUSTEDPUBLISHER,
00479    IDS_WARN_REMOVE_PLURAL_TRUSTEDPUBLISHER },
00480  { disallowed, IDS_WARN_REMOVE_DEFAULT },
00481 };
00482 
00483 static const struct CertMgrStoreInfo publisherStoreList[] = {
00484  { root, IDS_WARN_REMOVE_ROOT, IDS_WARN_REMOVE_PLURAL_ROOT },
00485  { trustedPublisher, IDS_WARN_REMOVE_TRUSTEDPUBLISHER,
00486    IDS_WARN_REMOVE_PLURAL_TRUSTEDPUBLISHER },
00487  { disallowed, IDS_WARN_REMOVE_PLURAL_DEFAULT },
00488 };
00489 
00490 struct CertMgrData
00491 {
00492     HIMAGELIST imageList;
00493     LPCWSTR title;
00494     DWORD nStores;
00495     const struct CertMgrStoreInfo *stores;
00496 };
00497 
00498 static void show_cert_stores(HWND hwnd, DWORD dwFlags, struct CertMgrData *data)
00499 {
00500     const struct CertMgrStoreInfo *storeList;
00501     int cStores, i;
00502     HWND tab = GetDlgItem(hwnd, IDC_MGR_STORES);
00503 
00504     if (dwFlags & CRYPTUI_CERT_MGR_PUBLISHER_TAB)
00505     {
00506         storeList = publisherStoreList;
00507         cStores = sizeof(publisherStoreList) / sizeof(publisherStoreList[0]);
00508     }
00509     else
00510     {
00511         storeList = defaultStoreList;
00512         cStores = sizeof(defaultStoreList) / sizeof(defaultStoreList[0]);
00513     }
00514     if (dwFlags & CRYPTUI_CERT_MGR_SINGLE_TAB_FLAG)
00515         cStores = 1;
00516     data->nStores = cStores;
00517     data->stores = storeList;
00518     for (i = 0; i < cStores; i++)
00519     {
00520         LPCWSTR name;
00521         TCITEMW item;
00522         HCERTSTORE store;
00523 
00524         if (!(name = CryptFindLocalizedName(storeList[i].name)))
00525             name = storeList[i].name;
00526         store = CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, 0,
00527          CERT_SYSTEM_STORE_CURRENT_USER, storeList[i].name);
00528         item.mask = TCIF_TEXT | TCIF_PARAM;
00529         item.pszText = (LPWSTR)name;
00530         item.lParam = (LPARAM)store;
00531         SendMessageW(tab, TCM_INSERTITEMW, i, (LPARAM)&item);
00532     }
00533 }
00534 
00535 static void free_certs(HWND lv)
00536 {
00537     LVITEMW item;
00538     int items = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0), i;
00539 
00540     for (i = 0; i < items; i++)
00541     {
00542         item.mask = LVIF_PARAM;
00543         item.iItem = i;
00544         item.iSubItem = 0;
00545         SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item);
00546         CertFreeCertificateContext((PCCERT_CONTEXT)item.lParam);
00547     }
00548 }
00549 
00550 static HCERTSTORE cert_mgr_index_to_store(HWND tab, int index)
00551 {
00552     TCITEMW item;
00553 
00554     item.mask = TCIF_PARAM;
00555     SendMessageW(tab, TCM_GETITEMW, index, (LPARAM)&item);
00556     return (HCERTSTORE)item.lParam;
00557 }
00558 
00559 static HCERTSTORE cert_mgr_current_store(HWND hwnd)
00560 {
00561     HWND tab = GetDlgItem(hwnd, IDC_MGR_STORES);
00562 
00563     return cert_mgr_index_to_store(tab, SendMessageW(tab, TCM_GETCURSEL, 0, 0));
00564 }
00565 
00566 static void close_stores(HWND tab)
00567 {
00568     int i, tabs = SendMessageW(tab, TCM_GETITEMCOUNT, 0, 0);
00569 
00570     for (i = 0; i < tabs; i++)
00571         CertCloseStore(cert_mgr_index_to_store(tab, i), 0);
00572 }
00573 
00574 static void refresh_store_certs(HWND hwnd)
00575 {
00576     HWND lv = GetDlgItem(hwnd, IDC_MGR_CERTS);
00577 
00578     free_certs(lv);
00579     SendMessageW(lv, LVM_DELETEALLITEMS, 0, 0);
00580     show_store_certs(hwnd, cert_mgr_current_store(hwnd));
00581 }
00582 
00583 typedef enum {
00584     CheckBitmapIndexUnchecked = 1,
00585     CheckBitmapIndexChecked = 2,
00586     CheckBitmapIndexDisabledUnchecked = 3,
00587     CheckBitmapIndexDisabledChecked = 4
00588 } CheckBitmapIndex;
00589 
00590 static void add_known_usage(HWND lv, PCCRYPT_OID_INFO info,
00591  CheckBitmapIndex state)
00592 {
00593     LVITEMW item;
00594 
00595     item.mask = LVIF_TEXT | LVIF_STATE | LVIF_PARAM;
00596     item.state = INDEXTOSTATEIMAGEMASK(state);
00597     item.stateMask = LVIS_STATEIMAGEMASK;
00598     item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
00599     item.iSubItem = 0;
00600     item.lParam = (LPARAM)info;
00601     item.pszText = (LPWSTR)info->pwszName;
00602     SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
00603 }
00604 
00605 static void add_known_usages_to_list(HWND lv, CheckBitmapIndex state)
00606 {
00607     PCCRYPT_OID_INFO *usages;
00608 
00609     if (WTHelperGetKnownUsages(1, &usages))
00610     {
00611         PCCRYPT_OID_INFO *ptr;
00612 
00613         for (ptr = usages; *ptr; ptr++)
00614             add_known_usage(lv, *ptr, state);
00615         WTHelperGetKnownUsages(2, &usages);
00616     }
00617 }
00618 
00619 static void toggle_usage(HWND hwnd, int iItem)
00620 {
00621     LVITEMW item;
00622     int res;
00623     HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
00624 
00625     item.mask = LVIF_STATE;
00626     item.iItem = iItem;
00627     item.iSubItem = 0;
00628     item.stateMask = LVIS_STATEIMAGEMASK;
00629     res = SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item);
00630     if (res)
00631     {
00632         int state = item.state >> 12;
00633 
00634         item.state = INDEXTOSTATEIMAGEMASK(
00635          state == CheckBitmapIndexChecked ? CheckBitmapIndexUnchecked :
00636          CheckBitmapIndexChecked);
00637         SendMessageW(lv, LVM_SETITEMSTATE, iItem, (LPARAM)&item);
00638     }
00639 }
00640 
00641 static LONG_PTR find_oid_in_list(HWND lv, LPCSTR oid)
00642 {
00643     PCCRYPT_OID_INFO oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
00644      (void *)oid, CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
00645     LONG_PTR ret;
00646 
00647     if (oidInfo)
00648     {
00649         LVFINDINFOW findInfo;
00650 
00651         findInfo.flags = LVFI_PARAM;
00652         findInfo.lParam = (LPARAM)oidInfo;
00653         ret = SendMessageW(lv, LVM_FINDITEMW, -1, (LPARAM)&findInfo);
00654     }
00655     else
00656     {
00657         LVFINDINFOA findInfo;
00658 
00659         findInfo.flags = LVFI_STRING;
00660         findInfo.psz = oid;
00661         ret = SendMessageW(lv, LVM_FINDITEMA, -1, (LPARAM)&findInfo);
00662     }
00663     return ret;
00664 }
00665 
00666 static void save_cert_mgr_usages(HWND hwnd)
00667 {
00668     static const WCHAR keyName[] = { 'S','o','f','t','w','a','r','e','\\','M',
00669      'i','c','r','o','s','o','f','t','\\','C','r','y','p','t','o','g','r','a',
00670      'p','h','y','\\','U','I','\\','C','e','r','t','m','g','r','\\','P','u',
00671      'r','p','o','s','e',0 };
00672     HKEY key;
00673     HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
00674     int purposes = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0), i;
00675     LVITEMW item;
00676     LPSTR str = NULL;
00677 
00678     item.mask = LVIF_STATE | LVIF_PARAM;
00679     item.iSubItem = 0;
00680     item.stateMask = LVIS_STATEIMAGEMASK;
00681     for (i = 0; i < purposes; i++)
00682     {
00683         item.iItem = i;
00684         if (SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item))
00685         {
00686             int state = item.state >> 12;
00687 
00688             if (state == CheckBitmapIndexUnchecked)
00689             {
00690                 CRYPT_OID_INFO *info = (CRYPT_OID_INFO *)item.lParam;
00691                 BOOL firstString = TRUE;
00692 
00693                 if (!str)
00694                     str = HeapAlloc(GetProcessHeap(), 0,
00695                      strlen(info->pszOID) + 1);
00696                 else
00697                 {
00698                     str = HeapReAlloc(GetProcessHeap(), 0, str,
00699                      strlen(str) + 1 + strlen(info->pszOID) + 1);
00700                     firstString = FALSE;
00701                 }
00702                 if (str)
00703                 {
00704                     LPSTR ptr = firstString ? str : str + strlen(str);
00705 
00706                     if (!firstString)
00707                         *ptr++ = ',';
00708                     strcpy(ptr, info->pszOID);
00709                 }
00710             }
00711         }
00712     }
00713     if (!RegCreateKeyExW(HKEY_CURRENT_USER, keyName, 0, NULL, 0, KEY_ALL_ACCESS,
00714      NULL, &key, NULL))
00715     {
00716         if (str)
00717             RegSetValueExA(key, "Purpose", 0, REG_SZ, (const BYTE *)str,
00718              strlen(str) + 1);
00719         else
00720             RegDeleteValueA(key, "Purpose");
00721         RegCloseKey(key);
00722     }
00723     HeapFree(GetProcessHeap(), 0, str);
00724 }
00725 
00726 static LRESULT CALLBACK cert_mgr_advanced_dlg_proc(HWND hwnd, UINT msg,
00727  WPARAM wp, LPARAM lp)
00728 {
00729     switch (msg)
00730     {
00731     case WM_INITDIALOG:
00732     {
00733         RECT rc;
00734         LVCOLUMNW column;
00735         HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
00736         HIMAGELIST imageList;
00737         LPSTR disabledUsages;
00738 
00739         GetWindowRect(lv, &rc);
00740         column.mask = LVCF_WIDTH;
00741         column.cx = rc.right - rc.left;
00742         SendMessageW(lv, LVM_INSERTCOLUMNW, 0, (LPARAM)&column);
00743         imageList = ImageList_Create(16, 16, ILC_COLOR4 | ILC_MASK, 4, 0);
00744         if (imageList)
00745         {
00746             HBITMAP bmp;
00747             COLORREF backColor = RGB(255, 0, 255);
00748 
00749             bmp = LoadBitmapW(hInstance, MAKEINTRESOURCEW(IDB_CHECKS));
00750             ImageList_AddMasked(imageList, bmp, backColor);
00751             DeleteObject(bmp);
00752             ImageList_SetBkColor(imageList, CLR_NONE);
00753             SendMessageW(lv, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)imageList);
00754             SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)imageList);
00755         }
00756         add_known_usages_to_list(lv, CheckBitmapIndexChecked);
00757         if ((disabledUsages = get_cert_mgr_usages()))
00758         {
00759             LPSTR ptr, comma;
00760 
00761             for (ptr = disabledUsages, comma = strchr(ptr, ','); ptr && *ptr;
00762              ptr = comma ? comma + 1 : NULL,
00763              comma = ptr ? strchr(ptr, ',') : NULL)
00764             {
00765                 LONG_PTR index;
00766 
00767                 if (comma)
00768                     *comma = 0;
00769                 if ((index = find_oid_in_list(lv, ptr)) != -1)
00770                     toggle_usage(hwnd, index);
00771             }
00772             HeapFree(GetProcessHeap(), 0, disabledUsages);
00773         }
00774         break;
00775     }
00776     case WM_NOTIFY:
00777     {
00778         NMHDR *hdr = (NMHDR *)lp;
00779         NMITEMACTIVATE *nm;
00780 
00781         switch (hdr->code)
00782         {
00783         case NM_CLICK:
00784             nm = (NMITEMACTIVATE *)lp;
00785             toggle_usage(hwnd, nm->iItem);
00786             SendMessageW(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0);
00787             break;
00788         }
00789         break;
00790     }
00791     case WM_COMMAND:
00792         switch (wp)
00793         {
00794         case IDOK:
00795             save_cert_mgr_usages(hwnd);
00796             ImageList_Destroy((HIMAGELIST)GetWindowLongPtrW(hwnd, DWLP_USER));
00797             EndDialog(hwnd, IDOK);
00798             break;
00799         case IDCANCEL:
00800             ImageList_Destroy((HIMAGELIST)GetWindowLongPtrW(hwnd, DWLP_USER));
00801             EndDialog(hwnd, IDCANCEL);
00802             break;
00803         }
00804         break;
00805     }
00806     return 0;
00807 }
00808 
00809 static void cert_mgr_clear_cert_selection(HWND hwnd)
00810 {
00811     WCHAR empty[] = { 0 };
00812 
00813     EnableWindow(GetDlgItem(hwnd, IDC_MGR_EXPORT), FALSE);
00814     EnableWindow(GetDlgItem(hwnd, IDC_MGR_REMOVE), FALSE);
00815     EnableWindow(GetDlgItem(hwnd, IDC_MGR_VIEW), FALSE);
00816     SendMessageW(GetDlgItem(hwnd, IDC_MGR_PURPOSES), WM_SETTEXT, 0,
00817      (LPARAM)empty);
00818     refresh_store_certs(hwnd);
00819 }
00820 
00821 static PCCERT_CONTEXT cert_mgr_index_to_cert(HWND hwnd, int index)
00822 {
00823     PCCERT_CONTEXT cert = NULL;
00824     LVITEMW item;
00825 
00826     item.mask = LVIF_PARAM;
00827     item.iItem = index;
00828     item.iSubItem = 0;
00829     if (SendMessageW(GetDlgItem(hwnd, IDC_MGR_CERTS), LVM_GETITEMW, 0,
00830      (LPARAM)&item))
00831         cert = (PCCERT_CONTEXT)item.lParam;
00832     return cert;
00833 }
00834 
00835 static void show_selected_cert(HWND hwnd, int index)
00836 {
00837     PCCERT_CONTEXT cert = cert_mgr_index_to_cert(hwnd, index);
00838 
00839     if (cert)
00840     {
00841         CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo;
00842 
00843         memset(&viewInfo, 0, sizeof(viewInfo));
00844         viewInfo.dwSize = sizeof(viewInfo);
00845         viewInfo.hwndParent = hwnd;
00846         viewInfo.pCertContext = cert;
00847         /* FIXME: this should be modal */
00848         CryptUIDlgViewCertificateW(&viewInfo, NULL);
00849     }
00850 }
00851 
00852 static void cert_mgr_show_cert_usages(HWND hwnd, int index)
00853 {
00854     HWND text = GetDlgItem(hwnd, IDC_MGR_PURPOSES);
00855     PCCERT_CONTEXT cert = cert_mgr_index_to_cert(hwnd, index);
00856     PCERT_ENHKEY_USAGE usage;
00857     DWORD size;
00858 
00859     /* Get enhanced key usage.  Have to check for a property and an extension
00860      * separately, because CertGetEnhancedKeyUsage will succeed and return an
00861      * empty usage if neither is set.  Unfortunately an empty usage implies
00862      * no usage is allowed, so we have to distinguish between the two cases.
00863      */
00864     if (CertGetEnhancedKeyUsage(cert, CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG,
00865      NULL, &size))
00866     {
00867         usage = HeapAlloc(GetProcessHeap(), 0, size);
00868         if (!CertGetEnhancedKeyUsage(cert,
00869          CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, usage, &size))
00870         {
00871             HeapFree(GetProcessHeap(), 0, usage);
00872             usage = NULL;
00873         }
00874     }
00875     else if (CertGetEnhancedKeyUsage(cert, CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG,
00876      NULL, &size))
00877     {
00878         usage = HeapAlloc(GetProcessHeap(), 0, size);
00879         if (!CertGetEnhancedKeyUsage(cert,
00880          CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, usage, &size))
00881         {
00882             HeapFree(GetProcessHeap(), 0, usage);
00883             usage = NULL;
00884         }
00885     }
00886     else
00887         usage = NULL;
00888     if (usage)
00889     {
00890         if (usage->cUsageIdentifier)
00891         {
00892             static const WCHAR commaSpace[] = { ',',' ',0 };
00893             DWORD i, len = 1;
00894             LPWSTR str, ptr;
00895 
00896             for (i = 0; i < usage->cUsageIdentifier; i++)
00897             {
00898                 PCCRYPT_OID_INFO info =
00899                  CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
00900                  usage->rgpszUsageIdentifier[i],
00901                  CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
00902 
00903                 if (info)
00904                     len += strlenW(info->pwszName);
00905                 else
00906                     len += strlen(usage->rgpszUsageIdentifier[i]);
00907                 if (i < usage->cUsageIdentifier - 1)
00908                     len += strlenW(commaSpace);
00909             }
00910             str = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
00911             if (str)
00912             {
00913                 for (i = 0, ptr = str; i < usage->cUsageIdentifier; i++)
00914                 {
00915                     PCCRYPT_OID_INFO info =
00916                      CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
00917                      usage->rgpszUsageIdentifier[i],
00918                      CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
00919 
00920                     if (info)
00921                     {
00922                         strcpyW(ptr, info->pwszName);
00923                         ptr += strlenW(info->pwszName);
00924                     }
00925                     else
00926                     {
00927                         LPCSTR src = usage->rgpszUsageIdentifier[i];
00928 
00929                         for (; *src; ptr++, src++)
00930                             *ptr = *src;
00931                         *ptr = 0;
00932                     }
00933                     if (i < usage->cUsageIdentifier - 1)
00934                     {
00935                         strcpyW(ptr, commaSpace);
00936                         ptr += strlenW(commaSpace);
00937                     }
00938                 }
00939                 *ptr = 0;
00940                 SendMessageW(text, WM_SETTEXT, 0, (LPARAM)str);
00941                 HeapFree(GetProcessHeap(), 0, str);
00942             }
00943             HeapFree(GetProcessHeap(), 0, usage);
00944         }
00945         else
00946         {
00947             WCHAR buf[MAX_STRING_LEN];
00948 
00949             LoadStringW(hInstance, IDS_ALLOWED_PURPOSE_NONE, buf,
00950              sizeof(buf) / sizeof(buf[0]));
00951             SendMessageW(text, WM_SETTEXT, 0, (LPARAM)buf);
00952         }
00953     }
00954     else
00955     {
00956         WCHAR buf[MAX_STRING_LEN];
00957 
00958         LoadStringW(hInstance, IDS_ALLOWED_PURPOSE_ALL, buf,
00959          sizeof(buf) / sizeof(buf[0]));
00960         SendMessageW(text, WM_SETTEXT, 0, (LPARAM)buf);
00961     }
00962 }
00963 
00964 static void cert_mgr_do_remove(HWND hwnd)
00965 {
00966     int tabIndex = SendMessageW(GetDlgItem(hwnd, IDC_MGR_STORES),
00967      TCM_GETCURSEL, 0, 0);
00968     struct CertMgrData *data =
00969      (struct CertMgrData *)GetWindowLongPtrW(hwnd, DWLP_USER);
00970 
00971     if (tabIndex < data->nStores)
00972     {
00973         HWND lv = GetDlgItem(hwnd, IDC_MGR_CERTS);
00974         WCHAR warning[MAX_STRING_LEN], title[MAX_STRING_LEN];
00975         LPCWSTR pTitle;
00976         int warningID;
00977 
00978         if (SendMessageW(lv, LVM_GETSELECTEDCOUNT, 0, 0) > 1)
00979             warningID = data->stores[tabIndex].removePluralWarning;
00980         else
00981             warningID = data->stores[tabIndex].removeWarning;
00982         if (data->title)
00983             pTitle = data->title;
00984         else
00985         {
00986             LoadStringW(hInstance, IDS_CERT_MGR, title,
00987              sizeof(title) / sizeof(title[0]));
00988             pTitle = title;
00989         }
00990         LoadStringW(hInstance, warningID, warning,
00991          sizeof(warning) / sizeof(warning[0]));
00992         if (MessageBoxW(hwnd, warning, pTitle, MB_YESNO) == IDYES)
00993         {
00994             int selection = -1;
00995 
00996             do {
00997                 selection = SendMessageW(lv, LVM_GETNEXTITEM, selection,
00998                  LVNI_SELECTED);
00999                 if (selection >= 0)
01000                 {
01001                     PCCERT_CONTEXT cert = cert_mgr_index_to_cert(hwnd,
01002                      selection);
01003 
01004                     CertDeleteCertificateFromStore(cert);
01005                 }
01006             } while (selection >= 0);
01007             cert_mgr_clear_cert_selection(hwnd);
01008         }
01009     }
01010 }
01011 
01012 static void cert_mgr_do_export(HWND hwnd)
01013 {
01014     HWND lv = GetDlgItem(hwnd, IDC_MGR_CERTS);
01015     int selectionCount = SendMessageW(lv, LVM_GETSELECTEDCOUNT, 0, 0);
01016 
01017     if (selectionCount == 1)
01018     {
01019         int selection = SendMessageW(lv, LVM_GETNEXTITEM, -1,
01020          LVNI_SELECTED);
01021 
01022         if (selection >= 0)
01023         {
01024             PCCERT_CONTEXT cert = cert_mgr_index_to_cert(hwnd, selection);
01025 
01026             if (cert)
01027             {
01028                 CRYPTUI_WIZ_EXPORT_INFO info;
01029 
01030                 info.dwSize = sizeof(info);
01031                 info.pwszExportFileName = NULL;
01032                 info.dwSubjectChoice = CRYPTUI_WIZ_EXPORT_CERT_CONTEXT;
01033                 info.u.pCertContext = cert;
01034                 info.cStores = 0;
01035                 CryptUIWizExport(0, hwnd, NULL, &info, NULL);
01036             }
01037         }
01038     }
01039     else if (selectionCount > 1)
01040     {
01041         HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
01042          CERT_STORE_CREATE_NEW_FLAG, NULL);
01043 
01044         if (store)
01045         {
01046             CRYPTUI_WIZ_EXPORT_INFO info;
01047             int selection = -1;
01048 
01049             info.dwSize = sizeof(info);
01050             info.pwszExportFileName = NULL;
01051             info.dwSubjectChoice =
01052              CRYPTUI_WIZ_EXPORT_CERT_STORE_CERTIFICATES_ONLY;
01053             info.u.hCertStore = store;
01054             info.cStores = 0;
01055             do {
01056                 selection = SendMessageW(lv, LVM_GETNEXTITEM, selection,
01057                  LVNI_SELECTED);
01058                 if (selection >= 0)
01059                 {
01060                     PCCERT_CONTEXT cert = cert_mgr_index_to_cert(hwnd,
01061                      selection);
01062 
01063                     CertAddCertificateContextToStore(store, cert,
01064                      CERT_STORE_ADD_ALWAYS, NULL);
01065                 }
01066             } while (selection >= 0);
01067             CryptUIWizExport(0, hwnd, NULL, &info, NULL);
01068             CertCloseStore(store, 0);
01069         }
01070     }
01071 }
01072 
01073 static int cert_mgr_sort_by_text(HWND lv, int col, int index1, int index2)
01074 {
01075     LVITEMW item;
01076     WCHAR buf1[MAX_STRING_LEN];
01077     WCHAR buf2[MAX_STRING_LEN];
01078 
01079     item.cchTextMax = sizeof(buf1) / sizeof(buf1[0]);
01080     item.mask = LVIF_TEXT;
01081     item.pszText = buf1;
01082     item.iItem = index1;
01083     item.iSubItem = col;
01084     SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item);
01085     item.pszText = buf2;
01086     item.iItem = index2;
01087     SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item);
01088     return strcmpW(buf1, buf2);
01089 }
01090 
01091 static int CALLBACK cert_mgr_sort_by_subject(LPARAM lp1, LPARAM lp2, LPARAM lp)
01092 {
01093     return cert_mgr_sort_by_text((HWND)lp, 0, lp1, lp2);
01094 }
01095 
01096 static int CALLBACK cert_mgr_sort_by_issuer(LPARAM lp1, LPARAM lp2, LPARAM lp)
01097 {
01098     return cert_mgr_sort_by_text((HWND)lp, 1, lp1, lp2);
01099 }
01100 
01101 static int CALLBACK cert_mgr_sort_by_date(LPARAM lp1, LPARAM lp2, LPARAM lp)
01102 {
01103     PCCERT_CONTEXT cert1 = (PCCERT_CONTEXT)lp1;
01104     PCCERT_CONTEXT cert2 = (PCCERT_CONTEXT)lp2;
01105     return CompareFileTime(&cert1->pCertInfo->NotAfter,
01106      &cert2->pCertInfo->NotAfter);
01107 }
01108 
01109 static int CALLBACK cert_mgr_sort_by_friendly_name(LPARAM lp1, LPARAM lp2,
01110  LPARAM lp)
01111 {
01112     return cert_mgr_sort_by_text((HWND)lp, 3, lp1, lp2);
01113 }
01114 
01115 static LRESULT CALLBACK cert_mgr_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
01116  LPARAM lp)
01117 {
01118     struct CertMgrData *data;
01119 
01120     switch (msg)
01121     {
01122     case WM_INITDIALOG:
01123     {
01124         PCCRYPTUI_CERT_MGR_STRUCT pCryptUICertMgr =
01125          (PCCRYPTUI_CERT_MGR_STRUCT)lp;
01126         HWND tab = GetDlgItem(hwnd, IDC_MGR_STORES);
01127 
01128         data = HeapAlloc(GetProcessHeap(), 0, sizeof(struct CertMgrData));
01129         if (!data)
01130             return 0;
01131         data->imageList = ImageList_Create(16, 16, ILC_COLOR4 | ILC_MASK, 2, 0);
01132         if (data->imageList)
01133         {
01134             HBITMAP bmp;
01135             COLORREF backColor = RGB(255, 0, 255);
01136 
01137             bmp = LoadBitmapW(hInstance, MAKEINTRESOURCEW(IDB_SMALL_ICONS));
01138             ImageList_AddMasked(data->imageList, bmp, backColor);
01139             DeleteObject(bmp);
01140             ImageList_SetBkColor(data->imageList, CLR_NONE);
01141             SendMessageW(GetDlgItem(hwnd, IDC_MGR_CERTS), LVM_SETIMAGELIST,
01142                          LVSIL_SMALL, (LPARAM)data->imageList);
01143         }
01144         SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
01145         data->title = pCryptUICertMgr->pwszTitle;
01146 
01147         initialize_purpose_selection(hwnd);
01148         add_cert_columns(hwnd);
01149         if (pCryptUICertMgr->pwszTitle)
01150             SendMessageW(hwnd, WM_SETTEXT, 0,
01151              (LPARAM)pCryptUICertMgr->pwszTitle);
01152         show_cert_stores(hwnd, pCryptUICertMgr->dwFlags, data);
01153         show_store_certs(hwnd, cert_mgr_index_to_store(tab, 0));
01154         break;
01155     }
01156     case WM_NOTIFY:
01157     {
01158         NMHDR *hdr = (NMHDR *)lp;
01159 
01160         switch (hdr->code)
01161         {
01162         case TCN_SELCHANGE:
01163             cert_mgr_clear_cert_selection(hwnd);
01164             break;
01165         case LVN_ITEMCHANGED:
01166         {
01167             WCHAR empty[] = { 0 };
01168             NMITEMACTIVATE *nm = (NMITEMACTIVATE*)lp;
01169             HWND lv = GetDlgItem(hwnd, IDC_MGR_CERTS);
01170             int numSelected = SendMessageW(lv, LVM_GETSELECTEDCOUNT, 0, 0);
01171 
01172             EnableWindow(GetDlgItem(hwnd, IDC_MGR_EXPORT), numSelected > 0);
01173             EnableWindow(GetDlgItem(hwnd, IDC_MGR_REMOVE), numSelected > 0);
01174             EnableWindow(GetDlgItem(hwnd, IDC_MGR_VIEW), numSelected == 1);
01175             if (numSelected == 1)
01176                 cert_mgr_show_cert_usages(hwnd, nm->iItem);
01177             else
01178                 SendMessageW(GetDlgItem(hwnd, IDC_MGR_PURPOSES), WM_SETTEXT, 0,
01179                  (LPARAM)empty);
01180             break;
01181         }
01182         case NM_DBLCLK:
01183             show_selected_cert(hwnd, ((NMITEMACTIVATE *)lp)->iItem);
01184             break;
01185         case LVN_KEYDOWN:
01186         {
01187             NMLVKEYDOWN *lvk = (NMLVKEYDOWN *)lp;
01188 
01189             if (lvk->wVKey == VK_DELETE)
01190                 cert_mgr_do_remove(hwnd);
01191             break;
01192         }
01193         case LVN_COLUMNCLICK:
01194         {
01195             NMLISTVIEW *nmlv = (NMLISTVIEW *)lp;
01196             HWND lv = GetDlgItem(hwnd, IDC_MGR_CERTS);
01197 
01198             /* FIXME: doesn't support swapping sort order between ascending
01199              * and descending.
01200              */
01201             switch (nmlv->iSubItem)
01202             {
01203             case 0:
01204                 SendMessageW(lv, LVM_SORTITEMSEX, (WPARAM)lv,
01205                  (LPARAM)cert_mgr_sort_by_subject);
01206                 break;
01207             case 1:
01208                 SendMessageW(lv, LVM_SORTITEMSEX, (WPARAM)lv,
01209                 (LPARAM)cert_mgr_sort_by_issuer);
01210                 break;
01211             case 2:
01212                 SendMessageW(lv, LVM_SORTITEMS, 0,
01213                  (LPARAM)cert_mgr_sort_by_date);
01214                 break;
01215             case 3:
01216                 SendMessageW(lv, LVM_SORTITEMSEX, (WPARAM)lv,
01217                  (LPARAM)cert_mgr_sort_by_friendly_name);
01218                 break;
01219             }
01220             break;
01221         }
01222         }
01223         break;
01224     }
01225     case WM_COMMAND:
01226         switch (wp)
01227         {
01228         case ((CBN_SELCHANGE << 16) | IDC_MGR_PURPOSE_SELECTION):
01229             cert_mgr_clear_cert_selection(hwnd);
01230             break;
01231         case IDC_MGR_IMPORT:
01232             if (CryptUIWizImport(0, hwnd, NULL, NULL,
01233              cert_mgr_current_store(hwnd)))
01234                 refresh_store_certs(hwnd);
01235             break;
01236         case IDC_MGR_ADVANCED:
01237             if (DialogBoxW(hInstance, MAKEINTRESOURCEW(IDD_CERT_MGR_ADVANCED),
01238              hwnd, cert_mgr_advanced_dlg_proc) == IDOK)
01239             {
01240                 HWND cb = GetDlgItem(hwnd, IDC_MGR_PURPOSE_SELECTION);
01241                 int index, len;
01242                 LPWSTR curString = NULL;
01243 
01244                 index = SendMessageW(cb, CB_GETCURSEL, 0, 0);
01245                 if (index >= 0)
01246                 {
01247                     len = SendMessageW(cb, CB_GETLBTEXTLEN, index, 0);
01248                     curString = HeapAlloc(GetProcessHeap(), 0,
01249                      (len + 1) * sizeof(WCHAR));
01250                     SendMessageW(cb, CB_GETLBTEXT, index, (LPARAM)curString);
01251                 }
01252                 SendMessageW(cb, CB_RESETCONTENT, 0, 0);
01253                 initialize_purpose_selection(hwnd);
01254                 if (curString)
01255                 {
01256                     index = SendMessageW(cb, CB_FINDSTRINGEXACT, -1,
01257                      (LPARAM)curString);
01258                     if (index >= 0)
01259                         SendMessageW(cb, CB_SETCURSEL, index, 0);
01260                     HeapFree(GetProcessHeap(), 0, curString);
01261                 }
01262                 refresh_store_certs(hwnd);
01263             }
01264             break;
01265         case IDC_MGR_VIEW:
01266         {
01267             HWND lv = GetDlgItem(hwnd, IDC_MGR_CERTS);
01268             int selection = SendMessageW(lv, LVM_GETNEXTITEM, -1,
01269              LVNI_SELECTED);
01270 
01271             if (selection >= 0)
01272                 show_selected_cert(hwnd, selection);
01273             break;
01274         }
01275         case IDC_MGR_EXPORT:
01276             cert_mgr_do_export(hwnd);
01277             break;
01278         case IDC_MGR_REMOVE:
01279             cert_mgr_do_remove(hwnd);
01280             break;
01281         case IDCANCEL:
01282             free_certs(GetDlgItem(hwnd, IDC_MGR_CERTS));
01283             close_stores(GetDlgItem(hwnd, IDC_MGR_STORES));
01284             data = (struct CertMgrData *)GetWindowLongPtrW(hwnd, DWLP_USER);
01285             ImageList_Destroy(data->imageList);
01286             HeapFree(GetProcessHeap(), 0, data);
01287             EndDialog(hwnd, IDCANCEL);
01288             break;
01289         }
01290         break;
01291     }
01292     return 0;
01293 }
01294 
01295 /***********************************************************************
01296  *      CryptUIDlgCertMgr (CRYPTUI.@)
01297  */
01298 BOOL WINAPI CryptUIDlgCertMgr(PCCRYPTUI_CERT_MGR_STRUCT pCryptUICertMgr)
01299 {
01300     TRACE("(%p)\n", pCryptUICertMgr);
01301 
01302     if (pCryptUICertMgr->dwSize != sizeof(CRYPTUI_CERT_MGR_STRUCT))
01303     {
01304         WARN("unexpected size %d\n", pCryptUICertMgr->dwSize);
01305         SetLastError(E_INVALIDARG);
01306         return FALSE;
01307     }
01308     DialogBoxParamW(hInstance, MAKEINTRESOURCEW(IDD_CERT_MGR),
01309      pCryptUICertMgr->hwndParent, cert_mgr_dlg_proc, (LPARAM)pCryptUICertMgr);
01310     return TRUE;
01311 }
01312 
01313 /* FIXME: real names are unknown, functions are undocumented */
01314 typedef struct _CRYPTUI_ENUM_SYSTEM_STORE_ARGS
01315 {
01316     DWORD dwFlags;
01317     void *pvSystemStoreLocationPara;
01318 } CRYPTUI_ENUM_SYSTEM_STORE_ARGS, *PCRYPTUI_ENUM_SYSTEM_STORE_ARGS;
01319 
01320 typedef struct _CRYPTUI_ENUM_DATA
01321 {
01322     DWORD                           cStores;
01323     HCERTSTORE                     *rghStore;
01324     DWORD                           cEnumArgs;
01325     PCRYPTUI_ENUM_SYSTEM_STORE_ARGS rgEnumArgs;
01326 } CRYPTUI_ENUM_DATA, *PCRYPTUI_ENUM_DATA;
01327 
01328 typedef BOOL (WINAPI *PFN_SELECTED_STORE_CB)(HCERTSTORE store, HWND hwnd,
01329  void *pvArg);
01330 
01331 /* Values for dwFlags */
01332 #define CRYPTUI_ENABLE_SHOW_PHYSICAL_STORE 0x00000001
01333 
01334 typedef struct _CRYPTUI_SELECTSTORE_INFO_A
01335 {
01336     DWORD                 dwSize;
01337     HWND                  parent;
01338     DWORD                 dwFlags;
01339     LPSTR                 pszTitle;
01340     LPSTR                 pszText;
01341     CRYPTUI_ENUM_DATA    *pEnumData;
01342     PFN_SELECTED_STORE_CB pfnSelectedStoreCallback;
01343     void                 *pvArg;
01344 } CRYPTUI_SELECTSTORE_INFO_A, *PCRYPTUI_SELECTSTORE_INFO_A;
01345 
01346 typedef struct _CRYPTUI_SELECTSTORE_INFO_W
01347 {
01348     DWORD                 dwSize;
01349     HWND                  parent;
01350     DWORD                 dwFlags;
01351     LPWSTR                pwszTitle;
01352     LPWSTR                pwszText;
01353     CRYPTUI_ENUM_DATA    *pEnumData;
01354     PFN_SELECTED_STORE_CB pfnSelectedStoreCallback;
01355     void                 *pvArg;
01356 } CRYPTUI_SELECTSTORE_INFO_W, *PCRYPTUI_SELECTSTORE_INFO_W;
01357 
01358 struct StoreInfo
01359 {
01360     enum {
01361         StoreHandle,
01362         SystemStore
01363     } type;
01364     union {
01365         HCERTSTORE store;
01366         LPWSTR name;
01367     } DUMMYUNIONNAME;
01368 };
01369 
01370 static BOOL WINAPI enum_store_callback(const void *pvSystemStore,
01371  DWORD dwFlags, PCERT_SYSTEM_STORE_INFO pStoreInfo, void *pvReserved,
01372  void *pvArg)
01373 {
01374     HWND tree = GetDlgItem(pvArg, IDC_STORE_LIST);
01375     TVINSERTSTRUCTW tvis;
01376     LPCWSTR localizedName;
01377     BOOL ret = TRUE;
01378 
01379     tvis.hParent = NULL;
01380     tvis.hInsertAfter = TVI_LAST;
01381     tvis.u.item.mask = TVIF_TEXT;
01382     if ((localizedName = CryptFindLocalizedName(pvSystemStore)))
01383     {
01384         struct StoreInfo *storeInfo = HeapAlloc(GetProcessHeap(), 0,
01385          sizeof(struct StoreInfo));
01386 
01387         if (storeInfo)
01388         {
01389             storeInfo->type = SystemStore;
01390             storeInfo->u.name = HeapAlloc(GetProcessHeap(), 0,
01391              (strlenW(pvSystemStore) + 1) * sizeof(WCHAR));
01392             if (storeInfo->u.name)
01393             {
01394                 tvis.u.item.mask |= TVIF_PARAM;
01395                 tvis.u.item.lParam = (LPARAM)storeInfo;
01396                 strcpyW(storeInfo->u.name, pvSystemStore);
01397             }
01398             else
01399             {
01400                 HeapFree(GetProcessHeap(), 0, storeInfo);
01401                 ret = FALSE;
01402             }
01403         }
01404         else
01405             ret = FALSE;
01406         tvis.u.item.pszText = (LPWSTR)localizedName;
01407     }
01408     else
01409         tvis.u.item.pszText = (LPWSTR)pvSystemStore;
01410     /* FIXME: need a folder icon for the store too */
01411     if (ret)
01412         SendMessageW(tree, TVM_INSERTITEMW, 0, (LPARAM)&tvis);
01413     return ret;
01414 }
01415 
01416 static void enumerate_stores(HWND hwnd, CRYPTUI_ENUM_DATA *pEnumData)
01417 {
01418     DWORD i;
01419     HWND tree = GetDlgItem(hwnd, IDC_STORE_LIST);
01420 
01421     for (i = 0; i < pEnumData->cEnumArgs; i++)
01422         CertEnumSystemStore(pEnumData->rgEnumArgs[i].dwFlags,
01423          pEnumData->rgEnumArgs[i].pvSystemStoreLocationPara,
01424          hwnd, enum_store_callback);
01425     for (i = 0; i < pEnumData->cStores; i++)
01426     {
01427         DWORD size;
01428 
01429         if (CertGetStoreProperty(pEnumData->rghStore[i],
01430          CERT_STORE_LOCALIZED_NAME_PROP_ID, NULL, &size))
01431         {
01432             LPWSTR name = HeapAlloc(GetProcessHeap(), 0, size);
01433 
01434             if (name)
01435             {
01436                 if (CertGetStoreProperty(pEnumData->rghStore[i],
01437                  CERT_STORE_LOCALIZED_NAME_PROP_ID, name, &size))
01438                 {
01439                     struct StoreInfo *storeInfo = HeapAlloc(GetProcessHeap(),
01440                      0, sizeof(struct StoreInfo));
01441 
01442                     if (storeInfo)
01443                     {
01444                         TVINSERTSTRUCTW tvis;
01445 
01446                         storeInfo->type = StoreHandle;
01447                         storeInfo->u.store = pEnumData->rghStore[i];
01448                         tvis.hParent = NULL;
01449                         tvis.hInsertAfter = TVI_LAST;
01450                         tvis.u.item.mask = TVIF_TEXT | TVIF_PARAM;
01451                         tvis.u.item.pszText = name;
01452                         tvis.u.item.lParam = (LPARAM)storeInfo;
01453                         SendMessageW(tree, TVM_INSERTITEMW, 0, (LPARAM)&tvis);
01454                     }
01455                 }
01456                 HeapFree(GetProcessHeap(), 0, name);
01457             }
01458         }
01459     }
01460 }
01461 
01462 static void free_store_info(HWND tree)
01463 {
01464     HTREEITEM next = (HTREEITEM)SendMessageW(tree, TVM_GETNEXTITEM, TVGN_CHILD,
01465      0);
01466 
01467     while (next)
01468     {
01469         TVITEMW item;
01470 
01471         memset(&item, 0, sizeof(item));
01472         item.mask = TVIF_HANDLE | TVIF_PARAM;
01473         item.hItem = next;
01474         SendMessageW(tree, TVM_GETITEMW, 0, (LPARAM)&item);
01475         if (item.lParam)
01476         {
01477             struct StoreInfo *storeInfo = (struct StoreInfo *)item.lParam;
01478 
01479             if (storeInfo->type == SystemStore)
01480                 HeapFree(GetProcessHeap(), 0, storeInfo->u.name);
01481             HeapFree(GetProcessHeap(), 0, storeInfo);
01482         }
01483         next = (HTREEITEM)SendMessageW(tree, TVM_GETNEXTITEM, TVGN_NEXT,
01484          (LPARAM)next);
01485     }
01486 }
01487 
01488 static HCERTSTORE selected_item_to_store(HWND tree, HTREEITEM hItem)
01489 {
01490     WCHAR buf[MAX_STRING_LEN];
01491     TVITEMW item;
01492     HCERTSTORE store;
01493 
01494     memset(&item, 0, sizeof(item));
01495     item.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_TEXT;
01496     item.hItem = hItem;
01497     item.cchTextMax = sizeof(buf) / sizeof(buf[0]);
01498     item.pszText = buf;
01499     SendMessageW(tree, TVM_GETITEMW, 0, (LPARAM)&item);
01500     if (item.lParam)
01501     {
01502         struct StoreInfo *storeInfo = (struct StoreInfo *)item.lParam;
01503 
01504         if (storeInfo->type == StoreHandle)
01505             store = storeInfo->u.store;
01506         else
01507             store = CertOpenSystemStoreW(0, storeInfo->u.name);
01508     }
01509     else
01510     {
01511         /* It's implicitly a system store */
01512         store = CertOpenSystemStoreW(0, buf);
01513     }
01514     return store;
01515 }
01516 
01517 struct SelectStoreInfo
01518 {
01519     PCRYPTUI_SELECTSTORE_INFO_W info;
01520     HCERTSTORE                  store;
01521 };
01522 
01523 static LRESULT CALLBACK select_store_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
01524  LPARAM lp)
01525 {
01526     struct SelectStoreInfo *selectInfo;
01527     LRESULT ret = 0;
01528 
01529     switch (msg)
01530     {
01531     case WM_INITDIALOG:
01532     {
01533         selectInfo = (struct SelectStoreInfo *)lp;
01534         SetWindowLongPtrW(hwnd, DWLP_USER, lp);
01535         if (selectInfo->info->pwszTitle)
01536             SendMessageW(hwnd, WM_SETTEXT, 0,
01537              (LPARAM)selectInfo->info->pwszTitle);
01538         if (selectInfo->info->pwszText)
01539             SendMessageW(GetDlgItem(hwnd, IDC_STORE_TEXT), WM_SETTEXT, 0,
01540              (LPARAM)selectInfo->info->pwszText);
01541         if (!(selectInfo->info->dwFlags & CRYPTUI_ENABLE_SHOW_PHYSICAL_STORE))
01542             ShowWindow(GetDlgItem(hwnd, IDC_SHOW_PHYSICAL_STORES), FALSE);
01543         enumerate_stores(hwnd, selectInfo->info->pEnumData);
01544         break;
01545     }
01546     case WM_COMMAND:
01547         switch (wp)
01548         {
01549         case IDOK:
01550         {
01551             HWND tree = GetDlgItem(hwnd, IDC_STORE_LIST);
01552             HTREEITEM selection = (HTREEITEM)SendMessageW(tree,
01553              TVM_GETNEXTITEM, TVGN_CARET, 0);
01554 
01555             selectInfo = (struct SelectStoreInfo *)GetWindowLongPtrW(hwnd,
01556              DWLP_USER);
01557             if (!selection)
01558             {
01559                 WCHAR title[MAX_STRING_LEN], error[MAX_STRING_LEN], *pTitle;
01560 
01561                 if (selectInfo->info->pwszTitle)
01562                     pTitle = selectInfo->info->pwszTitle;
01563                 else
01564                 {
01565                     LoadStringW(hInstance, IDS_SELECT_STORE_TITLE, title,
01566                      sizeof(title) / sizeof(title[0]));
01567                     pTitle = title;
01568                 }
01569                 LoadStringW(hInstance, IDS_SELECT_STORE, error,
01570                  sizeof(error) / sizeof(error[0]));
01571                 MessageBoxW(hwnd, error, pTitle, MB_ICONEXCLAMATION | MB_OK);
01572             }
01573             else
01574             {
01575                 HCERTSTORE store = selected_item_to_store(tree, selection);
01576 
01577                 if (!selectInfo->info->pfnSelectedStoreCallback ||
01578                  selectInfo->info->pfnSelectedStoreCallback(store, hwnd,
01579                  selectInfo->info->pvArg))
01580                 {
01581                     selectInfo->store = store;
01582                     free_store_info(tree);
01583                     EndDialog(hwnd, IDOK);
01584                 }
01585                 else
01586                     CertCloseStore(store, 0);
01587             }
01588             ret = TRUE;
01589             break;
01590         }
01591         case IDCANCEL:
01592             free_store_info(GetDlgItem(hwnd, IDC_STORE_LIST));
01593             EndDialog(hwnd, IDCANCEL);
01594             ret = TRUE;
01595             break;
01596         }
01597         break;
01598     }
01599     return ret;
01600 }
01601 
01602 /***********************************************************************
01603  *      CryptUIDlgSelectStoreW (CRYPTUI.@)
01604  */
01605 HCERTSTORE WINAPI CryptUIDlgSelectStoreW(PCRYPTUI_SELECTSTORE_INFO_W info)
01606 {
01607     struct SelectStoreInfo selectInfo = { info, NULL };
01608 
01609     TRACE("(%p)\n", info);
01610 
01611     if (info->dwSize != sizeof(CRYPTUI_SELECTSTORE_INFO_W))
01612     {
01613         WARN("unexpected size %d\n", info->dwSize);
01614         SetLastError(E_INVALIDARG);
01615         return NULL;
01616     }
01617     DialogBoxParamW(hInstance, MAKEINTRESOURCEW(IDD_SELECT_STORE), info->parent,
01618      select_store_dlg_proc, (LPARAM)&selectInfo);
01619     return selectInfo.store;
01620 }
01621 
01622 /***********************************************************************
01623  *      CryptUIDlgSelectStoreA (CRYPTUI.@)
01624  */
01625 HCERTSTORE WINAPI CryptUIDlgSelectStoreA(PCRYPTUI_SELECTSTORE_INFO_A info)
01626 {
01627     CRYPTUI_SELECTSTORE_INFO_W infoW;
01628     HCERTSTORE ret;
01629     int len;
01630 
01631     TRACE("(%p)\n", info);
01632 
01633     if (info->dwSize != sizeof(CRYPTUI_SELECTSTORE_INFO_A))
01634     {
01635         WARN("unexpected size %d\n", info->dwSize);
01636         SetLastError(E_INVALIDARG);
01637         return NULL;
01638     }
01639     memcpy(&infoW, info, sizeof(*info));
01640     if (info->pszTitle)
01641     {
01642         len = MultiByteToWideChar(CP_ACP, 0, info->pszTitle, -1, NULL, 0);
01643         infoW.pwszTitle = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
01644         MultiByteToWideChar(CP_ACP, 0, info->pszTitle, -1, infoW.pwszTitle,
01645          len);
01646     }
01647     if (info->pszText)
01648     {
01649         len = MultiByteToWideChar(CP_ACP, 0, info->pszText, -1, NULL, 0);
01650         infoW.pwszText = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
01651         MultiByteToWideChar(CP_ACP, 0, info->pszText, -1, infoW.pwszText, len);
01652     }
01653     ret = CryptUIDlgSelectStoreW(&infoW);
01654     HeapFree(GetProcessHeap(), 0, infoW.pwszText);
01655     HeapFree(GetProcessHeap(), 0, infoW.pwszTitle);
01656     return ret;
01657 }
01658 
01659 /***********************************************************************
01660  *      CryptUIDlgViewCertificateA (CRYPTUI.@)
01661  */
01662 BOOL WINAPI CryptUIDlgViewCertificateA(
01663  PCCRYPTUI_VIEWCERTIFICATE_STRUCTA pCertViewInfo, BOOL *pfPropertiesChanged)
01664 {
01665     CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo;
01666     LPWSTR title = NULL;
01667     BOOL ret;
01668 
01669     TRACE("(%p, %p)\n", pCertViewInfo, pfPropertiesChanged);
01670 
01671     memcpy(&viewInfo, pCertViewInfo, sizeof(viewInfo));
01672     if (pCertViewInfo->szTitle)
01673     {
01674         int len = MultiByteToWideChar(CP_ACP, 0, pCertViewInfo->szTitle, -1,
01675          NULL, 0);
01676 
01677         title = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
01678         if (title)
01679         {
01680             MultiByteToWideChar(CP_ACP, 0, pCertViewInfo->szTitle, -1, title,
01681              len);
01682             viewInfo.szTitle = title;
01683         }
01684         else
01685         {
01686             ret = FALSE;
01687             goto error;
01688         }
01689     }
01690     if (pCertViewInfo->cPropSheetPages)
01691     {
01692         FIXME("ignoring additional prop sheet pages\n");
01693         viewInfo.cPropSheetPages = 0;
01694     }
01695     ret = CryptUIDlgViewCertificateW(&viewInfo, pfPropertiesChanged);
01696     HeapFree(GetProcessHeap(), 0, title);
01697 error:
01698     return ret;
01699 }
01700 
01701 struct ReadStringStruct
01702 {
01703     LPCWSTR buf;
01704     LONG pos;
01705     LONG len;
01706 };
01707 
01708 static DWORD CALLBACK read_text_callback(DWORD_PTR dwCookie, LPBYTE buf,
01709  LONG cb, LONG *pcb)
01710 {
01711     struct ReadStringStruct *string = (struct ReadStringStruct *)dwCookie;
01712     LONG cch = min(cb / sizeof(WCHAR), string->len - string->pos);
01713 
01714     TRACE("(%p, %p, %d, %p)\n", string, buf, cb, pcb);
01715 
01716     memmove(buf, string->buf + string->pos, cch * sizeof(WCHAR));
01717     string->pos += cch;
01718     *pcb = cch * sizeof(WCHAR);
01719     return 0;
01720 }
01721 
01722 static void add_unformatted_text_to_control(HWND hwnd, LPCWSTR text, LONG len)
01723 {
01724     struct ReadStringStruct string;
01725     EDITSTREAM editstream;
01726 
01727     TRACE("(%p, %s)\n", hwnd, debugstr_wn(text, len));
01728 
01729     string.buf = text;
01730     string.pos = 0;
01731     string.len = len;
01732     editstream.dwCookie = (DWORD_PTR)&string;
01733     editstream.dwError = 0;
01734     editstream.pfnCallback = read_text_callback;
01735     SendMessageW(hwnd, EM_STREAMIN, SF_TEXT | SFF_SELECTION | SF_UNICODE,
01736      (LPARAM)&editstream);
01737 }
01738 
01739 static void add_string_resource_to_control(HWND hwnd, int id)
01740 {
01741     LPWSTR str;
01742     LONG len;
01743 
01744     len = LoadStringW(hInstance, id, (LPWSTR)&str, 0);
01745     add_unformatted_text_to_control(hwnd, str, len);
01746 }
01747 
01748 static void add_text_with_paraformat_to_control(HWND hwnd, LPCWSTR text,
01749  LONG len, const PARAFORMAT2 *fmt)
01750 {
01751     add_unformatted_text_to_control(hwnd, text, len);
01752     SendMessageW(hwnd, EM_SETPARAFORMAT, 0, (LPARAM)fmt);
01753 }
01754 
01755 static void add_string_resource_with_paraformat_to_control(HWND hwnd, int id,
01756  const PARAFORMAT2 *fmt)
01757 {
01758     LPWSTR str;
01759     LONG len;
01760 
01761     len = LoadStringW(hInstance, id, (LPWSTR)&str, 0);
01762     add_text_with_paraformat_to_control(hwnd, str, len, fmt);
01763 }
01764 
01765 static LPWSTR get_cert_name_string(PCCERT_CONTEXT pCertContext, DWORD dwType,
01766  DWORD dwFlags)
01767 {
01768     LPWSTR buf = NULL;
01769     DWORD len;
01770 
01771     len = CertGetNameStringW(pCertContext, dwType, dwFlags, NULL, NULL, 0);
01772     if (len)
01773     {
01774         buf = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
01775         if (buf)
01776             CertGetNameStringW(pCertContext, dwType, dwFlags, NULL, buf, len);
01777     }
01778     return buf;
01779 }
01780 
01781 static void add_cert_string_to_control(HWND hwnd, PCCERT_CONTEXT pCertContext,
01782  DWORD dwType, DWORD dwFlags)
01783 {
01784     LPWSTR name = get_cert_name_string(pCertContext, dwType, dwFlags);
01785 
01786     if (name)
01787     {
01788         /* Don't include NULL-terminator in output */
01789         DWORD len = lstrlenW(name);
01790 
01791         add_unformatted_text_to_control(hwnd, name, len);
01792         HeapFree(GetProcessHeap(), 0, name);
01793     }
01794 }
01795 
01796 static void add_icon_to_control(HWND hwnd, int id)
01797 {
01798     HRESULT hr;
01799     LPRICHEDITOLE richEditOle = NULL;
01800     LPOLEOBJECT object = NULL;
01801     CLSID clsid;
01802     LPOLECACHE oleCache = NULL;
01803     FORMATETC formatEtc;
01804     DWORD conn;
01805     LPDATAOBJECT dataObject = NULL;
01806     HBITMAP bitmap = NULL;
01807     RECT rect;
01808     STGMEDIUM stgm;
01809     LPOLECLIENTSITE clientSite = NULL;
01810     REOBJECT reObject;
01811 
01812     TRACE("(%p, %d)\n", hwnd, id);
01813 
01814     SendMessageW(hwnd, EM_GETOLEINTERFACE, 0, (LPARAM)&richEditOle);
01815     if (!richEditOle)
01816         goto end;
01817     hr = OleCreateDefaultHandler(&CLSID_NULL, NULL, &IID_IOleObject,
01818      (void**)&object);
01819     if (FAILED(hr))
01820         goto end;
01821     hr = IOleObject_GetUserClassID(object, &clsid);
01822     if (FAILED(hr))
01823         goto end;
01824     hr = IOleObject_QueryInterface(object, &IID_IOleCache, (void**)&oleCache);
01825     if (FAILED(hr))
01826         goto end;
01827     formatEtc.cfFormat = CF_BITMAP;
01828     formatEtc.ptd = NULL;
01829     formatEtc.dwAspect = DVASPECT_CONTENT;
01830     formatEtc.lindex = -1;
01831     formatEtc.tymed = TYMED_GDI;
01832     hr = IOleCache_Cache(oleCache, &formatEtc, 0, &conn);
01833     if (FAILED(hr))
01834         goto end;
01835     hr = IOleObject_QueryInterface(object, &IID_IDataObject,
01836      (void**)&dataObject);
01837     if (FAILED(hr))
01838         goto end;
01839     hr = IRichEditOle_GetClientSite(richEditOle, &clientSite);
01840     if (FAILED(hr))
01841         goto end;
01842     bitmap = LoadImageW(hInstance, MAKEINTRESOURCEW(id), IMAGE_BITMAP, 0, 0,
01843      LR_DEFAULTSIZE | LR_LOADTRANSPARENT);
01844     if (!bitmap)
01845         goto end;
01846     rect.left = rect.top = 0;
01847     rect.right = GetSystemMetrics(SM_CXICON);
01848     rect.bottom = GetSystemMetrics(SM_CYICON);
01849     stgm.tymed = TYMED_GDI;
01850     stgm.u.hBitmap = bitmap;
01851     stgm.pUnkForRelease = NULL;
01852     hr = IDataObject_SetData(dataObject, &formatEtc, &stgm, TRUE);
01853     if (FAILED(hr))
01854         goto end;
01855 
01856     reObject.cbStruct = sizeof(reObject);
01857     reObject.cp = REO_CP_SELECTION;
01858     reObject.clsid = clsid;
01859     reObject.poleobj = object;
01860     reObject.pstg = NULL;
01861     reObject.polesite = clientSite;
01862     reObject.sizel.cx = reObject.sizel.cy = 0;
01863     reObject.dvaspect = DVASPECT_CONTENT;
01864     reObject.dwFlags = 0;
01865     reObject.dwUser = 0;
01866 
01867     IRichEditOle_InsertObject(richEditOle, &reObject);
01868 
01869 end:
01870     if (clientSite)
01871         IOleClientSite_Release(clientSite);
01872     if (dataObject)
01873         IDataObject_Release(dataObject);
01874     if (oleCache)
01875         IOleCache_Release(oleCache);
01876     if (object)
01877         IOleObject_Release(object);
01878     if (richEditOle)
01879         IRichEditOle_Release(richEditOle);
01880 }
01881 
01882 #define MY_INDENT 200
01883 
01884 static void add_oid_text_to_control(HWND hwnd, char *oid)
01885 {
01886     WCHAR nl = '\n';
01887     PCCRYPT_OID_INFO oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, oid, 0);
01888     PARAFORMAT2 parFmt;
01889 
01890     parFmt.cbSize = sizeof(parFmt);
01891     parFmt.dwMask = PFM_STARTINDENT;
01892     parFmt.dxStartIndent = MY_INDENT * 3;
01893     if (oidInfo)
01894     {
01895         add_text_with_paraformat_to_control(hwnd, oidInfo->pwszName,
01896          lstrlenW(oidInfo->pwszName), &parFmt);
01897         add_unformatted_text_to_control(hwnd, &nl, 1);
01898     }
01899 }
01900 
01901 struct OIDToString
01902 {
01903     LPCSTR oid;
01904     int    id;
01905 };
01906 
01907 /* The following list MUST be lexicographically sorted by OID */
01908 static struct OIDToString oidMap[] = {
01909  /* 1.3.6.1.4.1.311.10.3.1 */
01910  { szOID_KP_CTL_USAGE_SIGNING, IDS_PURPOSE_CTL_USAGE_SIGNING },
01911  /* 1.3.6.1.4.1.311.10.3.4 */
01912  { szOID_KP_EFS, IDS_PURPOSE_EFS },
01913  /* 1.3.6.1.4.1.311.10.3.4.1 */
01914  { szOID_EFS_RECOVERY, IDS_PURPOSE_EFS_RECOVERY },
01915  /* 1.3.6.1.4.1.311.10.3.5 */
01916  { szOID_WHQL_CRYPTO, IDS_PURPOSE_WHQL },
01917  /* 1.3.6.1.4.1.311.10.3.6 */
01918  { szOID_NT5_CRYPTO, IDS_PURPOSE_NT5 },
01919  /* 1.3.6.1.4.1.311.10.3.7 */
01920  { szOID_OEM_WHQL_CRYPTO, IDS_PURPOSE_OEM_WHQL },
01921  /* 1.3.6.1.4.1.311.10.3.8 */
01922  { szOID_EMBEDDED_NT_CRYPTO, IDS_PURPOSE_EMBEDDED_NT },
01923  /* 1.3.6.1.4.1.311.10.3.9 */
01924  { szOID_ROOT_LIST_SIGNER, IDS_PURPOSE_ROOT_LIST_SIGNER },
01925  /* 1.3.6.1.4.1.311.10.3.10 */
01926  { szOID_KP_QUALIFIED_SUBORDINATION, IDS_PURPOSE_QUALIFIED_SUBORDINATION },
01927  /* 1.3.6.1.4.1.311.10.3.11 */
01928  { szOID_KP_KEY_RECOVERY, IDS_PURPOSE_KEY_RECOVERY },
01929  /* 1.3.6.1.4.1.311.10.3.12 */
01930  { szOID_KP_DOCUMENT_SIGNING, IDS_PURPOSE_DOCUMENT_SIGNING },
01931  /* 1.3.6.1.4.1.311.10.3.13 */
01932  { szOID_KP_LIFETIME_SIGNING, IDS_PURPOSE_LIFETIME_SIGNING },
01933  /* 1.3.6.1.4.1.311.10.5.1 */
01934  { szOID_DRM, IDS_PURPOSE_DRM },
01935  /* 1.3.6.1.4.1.311.10.6.1 */
01936  { szOID_LICENSES, IDS_PURPOSE_LICENSES },
01937  /* 1.3.6.1.4.1.311.10.6.2 */
01938  { szOID_LICENSE_SERVER, IDS_PURPOSE_LICENSE_SERVER },
01939  /* 1.3.6.1.4.1.311.20.2.1 */
01940  { szOID_ENROLLMENT_AGENT, IDS_PURPOSE_ENROLLMENT_AGENT },
01941  /* 1.3.6.1.4.1.311.20.2.2 */
01942  { szOID_KP_SMARTCARD_LOGON, IDS_PURPOSE_SMARTCARD_LOGON },
01943  /* 1.3.6.1.4.1.311.21.5 */
01944  { szOID_KP_CA_EXCHANGE, IDS_PURPOSE_CA_EXCHANGE },
01945  /* 1.3.6.1.4.1.311.21.6 */
01946  { szOID_KP_KEY_RECOVERY_AGENT, IDS_PURPOSE_KEY_RECOVERY_AGENT },
01947  /* 1.3.6.1.4.1.311.21.19 */
01948  { szOID_DS_EMAIL_REPLICATION, IDS_PURPOSE_DS_EMAIL_REPLICATION },
01949  /* 1.3.6.1.5.5.7.3.1 */
01950  { szOID_PKIX_KP_SERVER_AUTH, IDS_PURPOSE_SERVER_AUTH },
01951  /* 1.3.6.1.5.5.7.3.2 */
01952  { szOID_PKIX_KP_CLIENT_AUTH, IDS_PURPOSE_CLIENT_AUTH },
01953  /* 1.3.6.1.5.5.7.3.3 */
01954  { szOID_PKIX_KP_CODE_SIGNING, IDS_PURPOSE_CODE_SIGNING },
01955  /* 1.3.6.1.5.5.7.3.4 */
01956  { szOID_PKIX_KP_EMAIL_PROTECTION, IDS_PURPOSE_EMAIL_PROTECTION },
01957  /* 1.3.6.1.5.5.7.3.5 */
01958  { szOID_PKIX_KP_IPSEC_END_SYSTEM, IDS_PURPOSE_IPSEC },
01959  /* 1.3.6.1.5.5.7.3.6 */
01960  { szOID_PKIX_KP_IPSEC_TUNNEL, IDS_PURPOSE_IPSEC },
01961  /* 1.3.6.1.5.5.7.3.7 */
01962  { szOID_PKIX_KP_IPSEC_USER, IDS_PURPOSE_IPSEC },
01963  /* 1.3.6.1.5.5.7.3.8 */
01964  { szOID_PKIX_KP_TIMESTAMP_SIGNING, IDS_PURPOSE_TIMESTAMP_SIGNING },
01965 };
01966 
01967 static struct OIDToString *findSupportedOID(LPCSTR oid)
01968 {
01969     int indexHigh = sizeof(oidMap) / sizeof(oidMap[0]) - 1, indexLow = 0;
01970 
01971     while (indexLow <= indexHigh)
01972     {
01973         int cmp, i = (indexLow + indexHigh) / 2;
01974         if (!(cmp = strcmp(oid, oidMap[i].oid)))
01975             return &oidMap[i];
01976         if (cmp > 0)
01977             indexLow = i + 1;
01978         else
01979             indexHigh = i - 1;
01980     }
01981     return NULL;
01982 }
01983 
01984 static void add_local_oid_text_to_control(HWND text, LPCSTR oid)
01985 {
01986     struct OIDToString *entry;
01987     WCHAR nl = '\n';
01988     PARAFORMAT2 parFmt;
01989 
01990     parFmt.cbSize = sizeof(parFmt);
01991     parFmt.dwMask = PFM_STARTINDENT;
01992     parFmt.dxStartIndent = MY_INDENT * 3;
01993     if ((entry = findSupportedOID(oid)))
01994     {
01995         WCHAR *str, *linebreak, *ptr;
01996         BOOL multiline = FALSE;
01997         int len;
01998 
01999         len = LoadStringW(hInstance, entry->id, (LPWSTR)&str, 0);
02000         ptr = str;
02001         do {
02002             if ((linebreak = memchrW(ptr, '\n', len)))
02003             {
02004                 WCHAR copy[MAX_STRING_LEN];
02005 
02006                 multiline = TRUE;
02007                 /* The source string contains a newline, which the richedit
02008                  * control won't find since it's interpreted as a paragraph
02009                  * break.  Therefore copy up to the newline.  lstrcpynW always
02010                  * NULL-terminates, so pass one more than the length of the
02011                  * source line so the copy includes the entire line and the
02012                  * NULL-terminator.
02013                  */
02014                 lstrcpynW(copy, ptr, linebreak - ptr + 1);
02015                 add_text_with_paraformat_to_control(text, copy,
02016                  linebreak - ptr, &parFmt);
02017                 ptr = linebreak + 1;
02018                 add_unformatted_text_to_control(text, &nl, 1);
02019             }
02020             else if (multiline && *ptr)
02021             {
02022                 /* Add the last line */
02023                 add_text_with_paraformat_to_control(text, ptr,
02024                  len - (ptr - str), &parFmt);
02025                 add_unformatted_text_to_control(text, &nl, 1);
02026             }
02027         } while (linebreak);
02028         if (!multiline)
02029         {
02030             add_text_with_paraformat_to_control(text, str, len, &parFmt);
02031             add_unformatted_text_to_control(text, &nl, 1);
02032         }
02033     }
02034     else
02035     {
02036         WCHAR *oidW = HeapAlloc(GetProcessHeap(), 0,
02037          (strlen(oid) + 1) * sizeof(WCHAR));
02038 
02039         if (oidW)
02040         {
02041             LPCSTR src;
02042             WCHAR *dst;
02043 
02044             for (src = oid, dst = oidW; *src; src++, dst++)
02045                 *dst = *src;
02046             *dst = 0;
02047             add_text_with_paraformat_to_control(text, oidW, lstrlenW(oidW),
02048              &parFmt);
02049             add_unformatted_text_to_control(text, &nl, 1);
02050             HeapFree(GetProcessHeap(), 0, oidW);
02051         }
02052     }
02053 }
02054 
02055 static void display_app_usages(HWND text, PCCERT_CONTEXT cert,
02056  BOOL *anyUsageAdded)
02057 {
02058     static char any_app_policy[] = szOID_ANY_APPLICATION_POLICY;
02059     WCHAR nl = '\n';
02060     CHARFORMATW charFmt;
02061     PCERT_EXTENSION policyExt;
02062     if (!*anyUsageAdded)
02063     {
02064         PARAFORMAT2 parFmt;
02065 
02066         parFmt.cbSize = sizeof(parFmt);
02067         parFmt.dwMask = PFM_STARTINDENT;
02068         parFmt.dxStartIndent = MY_INDENT;
02069         add_string_resource_with_paraformat_to_control(text,
02070          IDS_CERT_INFO_PURPOSES, &parFmt);
02071         add_unformatted_text_to_control(text, &nl, 1);
02072         *anyUsageAdded = TRUE;
02073     }
02074     memset(&charFmt, 0, sizeof(charFmt));
02075     charFmt.cbSize = sizeof(charFmt);
02076     charFmt.dwMask = CFM_BOLD;
02077     charFmt.dwEffects = 0;
02078     SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
02079     if ((policyExt = CertFindExtension(szOID_APPLICATION_CERT_POLICIES,
02080      cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension)))
02081     {
02082         CERT_POLICIES_INFO *policies;
02083         DWORD size;
02084 
02085         if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT_POLICIES,
02086          policyExt->Value.pbData, policyExt->Value.cbData,
02087          CRYPT_DECODE_ALLOC_FLAG, NULL, &policies, &size))
02088         {
02089             DWORD i;
02090 
02091             for (i = 0; i < policies->cPolicyInfo; i++)
02092             {
02093                 DWORD j;
02094 
02095                 for (j = 0; j < policies->rgPolicyInfo[i].cPolicyQualifier; j++)
02096                     add_local_oid_text_to_control(text,
02097                      policies->rgPolicyInfo[i].rgPolicyQualifier[j].
02098                      pszPolicyQualifierId);
02099             }
02100             LocalFree(policies);
02101         }
02102     }
02103     else
02104         add_oid_text_to_control(text, any_app_policy);
02105 }
02106 
02107 static BOOL display_cert_usages(HWND text, PCCERT_CONTEXT cert,
02108  BOOL *anyUsageAdded)
02109 {
02110     WCHAR nl = '\n';
02111     DWORD size;
02112     BOOL badUsages = FALSE;
02113 
02114     if (CertGetEnhancedKeyUsage(cert, 0, NULL, &size))
02115     {
02116         CHARFORMATW charFmt;
02117         static char any_cert_policy[] = szOID_ANY_CERT_POLICY;
02118         PCERT_ENHKEY_USAGE usage = HeapAlloc(GetProcessHeap(), 0, size);
02119 
02120         if (usage)
02121         {
02122             if (CertGetEnhancedKeyUsage(cert, 0, usage, &size))
02123             {
02124                 DWORD i;
02125 
02126                 if (!*anyUsageAdded)
02127                 {
02128                     PARAFORMAT2 parFmt;
02129 
02130                     parFmt.cbSize = sizeof(parFmt);
02131                     parFmt.dwMask = PFM_STARTINDENT;
02132                     parFmt.dxStartIndent = MY_INDENT;
02133                     add_string_resource_with_paraformat_to_control(text,
02134                      IDS_CERT_INFO_PURPOSES, &parFmt);
02135                     add_unformatted_text_to_control(text, &nl, 1);
02136                     *anyUsageAdded = TRUE;
02137                 }
02138                 memset(&charFmt, 0, sizeof(charFmt));
02139                 charFmt.cbSize = sizeof(charFmt);
02140                 charFmt.dwMask = CFM_BOLD;
02141                 charFmt.dwEffects = 0;
02142                 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION,
02143                  (LPARAM)&charFmt);
02144                 if (!usage->cUsageIdentifier)
02145                     add_oid_text_to_control(text, any_cert_policy);
02146                 else
02147                     for (i = 0; i < usage->cUsageIdentifier; i++)
02148                         add_local_oid_text_to_control(text,
02149                          usage->rgpszUsageIdentifier[i]);
02150             }
02151             else
02152                 badUsages = TRUE;
02153             HeapFree(GetProcessHeap(), 0, usage);
02154         }
02155         else
02156             badUsages = TRUE;
02157     }
02158     else
02159         badUsages = TRUE;
02160     return badUsages;
02161 }
02162 
02163 static void set_policy_text(HWND text,
02164  PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo)
02165 {
02166     BOOL includeCertUsages = FALSE, includeAppUsages = FALSE;
02167     BOOL badUsages = FALSE, anyUsageAdded = FALSE;
02168 
02169     if (pCertViewInfo->cPurposes)
02170     {
02171         DWORD i;
02172 
02173         for (i = 0; i < pCertViewInfo->cPurposes; i++)
02174         {
02175             if (!strcmp(pCertViewInfo->rgszPurposes[i], szOID_ANY_CERT_POLICY))
02176                 includeCertUsages = TRUE;
02177             else if (!strcmp(pCertViewInfo->rgszPurposes[i],
02178              szOID_ANY_APPLICATION_POLICY))
02179                 includeAppUsages = TRUE;
02180             else
02181                 badUsages = TRUE;
02182         }
02183     }
02184     else
02185         includeAppUsages = includeCertUsages = TRUE;
02186     if (includeAppUsages)
02187         display_app_usages(text, pCertViewInfo->pCertContext, &anyUsageAdded);
02188     if (includeCertUsages)
02189         badUsages = display_cert_usages(text, pCertViewInfo->pCertContext,
02190          &anyUsageAdded);
02191     if (badUsages)
02192     {
02193         PARAFORMAT2 parFmt;
02194 
02195         parFmt.cbSize = sizeof(parFmt);
02196         parFmt.dwMask = PFM_STARTINDENT;
02197         parFmt.dxStartIndent = MY_INDENT;
02198         add_string_resource_with_paraformat_to_control(text,
02199          IDS_CERT_INFO_BAD_PURPOSES, &parFmt);
02200     }
02201 }
02202 
02203 static CRYPT_OBJID_BLOB *find_policy_qualifier(CERT_POLICIES_INFO *policies,
02204  LPCSTR policyOid)
02205 {
02206     CRYPT_OBJID_BLOB *ret = NULL;
02207     DWORD i;
02208 
02209     for (i = 0; !ret && i < policies->cPolicyInfo; i++)
02210     {
02211         DWORD j;
02212 
02213         for (j = 0; !ret && j < policies->rgPolicyInfo[i].cPolicyQualifier; j++)
02214             if (!strcmp(policies->rgPolicyInfo[i].rgPolicyQualifier[j].
02215              pszPolicyQualifierId, policyOid))
02216                 ret = &policies->rgPolicyInfo[i].rgPolicyQualifier[j].
02217                  Qualifier;
02218     }
02219     return ret;
02220 }
02221 
02222 static WCHAR *get_cps_str_from_qualifier(const CRYPT_OBJID_BLOB *qualifier)
02223 {
02224     LPWSTR qualifierStr = NULL;
02225     CERT_NAME_VALUE *qualifierValue;
02226     DWORD size;
02227 
02228     if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_NAME_VALUE,
02229      qualifier->pbData, qualifier->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL,
02230      &qualifierValue, &size))
02231     {
02232         size = CertRDNValueToStrW(qualifierValue->dwValueType,
02233          &qualifierValue->Value, NULL, 0);
02234         qualifierStr = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
02235         if (qualifierStr)
02236             CertRDNValueToStrW(qualifierValue->dwValueType,
02237              &qualifierValue->Value, qualifierStr, size);
02238         LocalFree(qualifierValue);
02239     }
02240     return qualifierStr;
02241 }
02242 
02243 static WCHAR *get_user_notice_from_qualifier(const CRYPT_OBJID_BLOB *qualifier)
02244 {
02245     LPWSTR str = NULL;
02246     CERT_POLICY_QUALIFIER_USER_NOTICE *qualifierValue;
02247     DWORD size;
02248 
02249     if (CryptDecodeObjectEx(X509_ASN_ENCODING,
02250      X509_PKIX_POLICY_QUALIFIER_USERNOTICE,
02251      qualifier->pbData, qualifier->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL,
02252      &qualifierValue, &size))
02253     {
02254         str = HeapAlloc(GetProcessHeap(), 0,
02255          (strlenW(qualifierValue->pszDisplayText) + 1) * sizeof(WCHAR));
02256         if (str)
02257             strcpyW(str, qualifierValue->pszDisplayText);
02258         LocalFree(qualifierValue);
02259     }
02260     return str;
02261 }
02262 
02263 struct IssuerStatement
02264 {
02265     LPWSTR cps;
02266     LPWSTR userNotice;
02267 };
02268 
02269 static void set_issuer_statement(HWND hwnd,
02270  PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo)
02271 {
02272     PCERT_EXTENSION policyExt;
02273 
02274     if (!(pCertViewInfo->dwFlags & CRYPTUI_DISABLE_ISSUERSTATEMENT) &&
02275      (policyExt = CertFindExtension(szOID_CERT_POLICIES,
02276      pCertViewInfo->pCertContext->pCertInfo->cExtension,
02277      pCertViewInfo->pCertContext->pCertInfo->rgExtension)))
02278     {
02279         CERT_POLICIES_INFO *policies;
02280         DWORD size;
02281 
02282         if (CryptDecodeObjectEx(X509_ASN_ENCODING, policyExt->pszObjId,
02283          policyExt->Value.pbData, policyExt->Value.cbData,
02284          CRYPT_DECODE_ALLOC_FLAG, NULL, &policies, &size))
02285         {
02286             CRYPT_OBJID_BLOB *qualifier;
02287             LPWSTR cps = NULL, userNotice = NULL;
02288 
02289             if ((qualifier = find_policy_qualifier(policies,
02290              szOID_PKIX_POLICY_QUALIFIER_CPS)))
02291                 cps = get_cps_str_from_qualifier(qualifier);
02292             if ((qualifier = find_policy_qualifier(policies,
02293              szOID_PKIX_POLICY_QUALIFIER_USERNOTICE)))
02294                 userNotice = get_user_notice_from_qualifier(qualifier);
02295             if (cps || userNotice)
02296             {
02297                 struct IssuerStatement *issuerStatement =
02298                  HeapAlloc(GetProcessHeap(), 0, sizeof(struct IssuerStatement));
02299 
02300                 if (issuerStatement)
02301                 {
02302                     issuerStatement->cps = cps;
02303                     issuerStatement->userNotice = userNotice;
02304                     EnableWindow(GetDlgItem(hwnd, IDC_ISSUERSTATEMENT), TRUE);
02305                     SetWindowLongPtrW(hwnd, DWLP_USER,
02306                      (ULONG_PTR)issuerStatement);
02307                 }
02308             }
02309             LocalFree(policies);
02310         }
02311     }
02312 }
02313 
02314 static void set_cert_info(HWND hwnd,
02315  PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo)
02316 {
02317     CHARFORMATW charFmt;
02318     PARAFORMAT2 parFmt;
02319     HWND icon = GetDlgItem(hwnd, IDC_CERTIFICATE_ICON);
02320     HWND text = GetDlgItem(hwnd, IDC_CERTIFICATE_INFO);
02321     CRYPT_PROVIDER_SGNR *provSigner = WTHelperGetProvSignerFromChain(
02322      (CRYPT_PROVIDER_DATA *)pCertViewInfo->u.pCryptProviderData,
02323      pCertViewInfo->idxSigner, pCertViewInfo->fCounterSigner,
02324      pCertViewInfo->idxCounterSigner);
02325     CRYPT_PROVIDER_CERT *root =
02326      &provSigner->pasCertChain[provSigner->csCertChain - 1];
02327 
02328     if (!provSigner->pChainContext ||
02329      (provSigner->pChainContext->TrustStatus.dwErrorStatus &
02330      CERT_TRUST_IS_PARTIAL_CHAIN))
02331         add_icon_to_control(icon, IDB_CERT_WARNING);
02332     else if (!root->fTrustedRoot)
02333         add_icon_to_control(icon, IDB_CERT_ERROR);
02334     else
02335         add_icon_to_control(icon, IDB_CERT);
02336 
02337     memset(&charFmt, 0, sizeof(charFmt));
02338     charFmt.cbSize = sizeof(charFmt);
02339     charFmt.dwMask = CFM_BOLD;
02340     charFmt.dwEffects = CFE_BOLD;
02341     SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
02342     /* FIXME: vertically center text */
02343     parFmt.cbSize = sizeof(parFmt);
02344     parFmt.dwMask = PFM_STARTINDENT;
02345     parFmt.dxStartIndent = MY_INDENT;
02346     add_string_resource_with_paraformat_to_control(text,
02347      IDS_CERTIFICATEINFORMATION, &parFmt);
02348 
02349     text = GetDlgItem(hwnd, IDC_CERTIFICATE_STATUS);
02350     SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
02351     if (provSigner->dwError == TRUST_E_CERT_SIGNATURE)
02352         add_string_resource_with_paraformat_to_control(text,
02353          IDS_CERT_INFO_BAD_SIG, &parFmt);
02354     else if (!provSigner->pChainContext ||
02355      (provSigner->pChainContext->TrustStatus.dwErrorStatus &
02356      CERT_TRUST_IS_PARTIAL_CHAIN))
02357         add_string_resource_with_paraformat_to_control(text,
02358          IDS_CERT_INFO_PARTIAL_CHAIN, &parFmt);
02359     else if (!root->fTrustedRoot)
02360     {
02361         if (provSigner->csCertChain == 1 && root->fSelfSigned)
02362             add_string_resource_with_paraformat_to_control(text,
02363              IDS_CERT_INFO_UNTRUSTED_CA, &parFmt);
02364         else
02365             add_string_resource_with_paraformat_to_control(text,
02366              IDS_CERT_INFO_UNTRUSTED_ROOT, &parFmt);
02367     }
02368     else
02369     {
02370         set_policy_text(text, pCertViewInfo);
02371         set_issuer_statement(hwnd, pCertViewInfo);
02372     }
02373 }
02374 
02375 static void set_cert_name_string(HWND hwnd, PCCERT_CONTEXT cert,
02376  DWORD nameFlags, int heading)
02377 {
02378     WCHAR nl = '\n';
02379     HWND text = GetDlgItem(hwnd, IDC_CERTIFICATE_NAMES);
02380     CHARFORMATW charFmt;
02381     PARAFORMAT2 parFmt;
02382 
02383     memset(&charFmt, 0, sizeof(charFmt));
02384     charFmt.cbSize = sizeof(charFmt);
02385     charFmt.dwMask = CFM_BOLD;
02386     charFmt.dwEffects = CFE_BOLD;
02387     SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
02388     parFmt.cbSize = sizeof(parFmt);
02389     parFmt.dwMask = PFM_STARTINDENT;
02390     parFmt.dxStartIndent = MY_INDENT * 3;
02391     add_string_resource_with_paraformat_to_control(text, heading, &parFmt);
02392     charFmt.dwEffects = 0;
02393     SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
02394     add_cert_string_to_control(text, cert, CERT_NAME_SIMPLE_DISPLAY_TYPE,
02395      nameFlags);
02396     add_unformatted_text_to_control(text, &nl, 1);
02397     add_unformatted_text_to_control(text, &nl, 1);
02398     add_unformatted_text_to_control(text, &nl, 1);
02399 
02400 }
02401 
02402 static void add_date_string_to_control(HWND hwnd, const FILETIME *fileTime)
02403 {
02404     WCHAR dateFmt[80]; /* sufficient for all versions of LOCALE_SSHORTDATE */
02405     WCHAR date[80];
02406     SYSTEMTIME sysTime;
02407 
02408     GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT, LOCALE_SSHORTDATE, dateFmt,
02409      sizeof(dateFmt) / sizeof(dateFmt[0]));
02410     FileTimeToSystemTime(fileTime, &sysTime);
02411     GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, date,
02412      sizeof(date) / sizeof(date[0]));
02413     add_unformatted_text_to_control(hwnd, date, lstrlenW(date));
02414 }
02415 
02416 static void set_cert_validity_period(HWND hwnd, PCCERT_CONTEXT cert)
02417 {
02418     WCHAR nl = '\n';
02419     HWND text = GetDlgItem(hwnd, IDC_CERTIFICATE_NAMES);
02420     CHARFORMATW charFmt;
02421     PARAFORMAT2 parFmt;
02422 
02423     memset(&charFmt, 0, sizeof(charFmt));
02424     charFmt.cbSize = sizeof(charFmt);
02425     charFmt.dwMask = CFM_BOLD;
02426     charFmt.dwEffects = CFE_BOLD;
02427     SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
02428     parFmt.cbSize = sizeof(parFmt);
02429     parFmt.dwMask = PFM_STARTINDENT;
02430     parFmt.dxStartIndent = MY_INDENT * 3;
02431     add_string_resource_with_paraformat_to_control(text, IDS_VALID_FROM,
02432      &parFmt);
02433     charFmt.dwEffects = 0;
02434     SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
02435     add_date_string_to_control(text, &cert->pCertInfo->NotBefore);
02436     charFmt.dwEffects = CFE_BOLD;
02437     SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
02438     add_string_resource_to_control(text, IDS_VALID_TO);
02439     charFmt.dwEffects = 0;
02440     SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
02441     add_date_string_to_control(text, &cert->pCertInfo->NotAfter);
02442     add_unformatted_text_to_control(text, &nl, 1);
02443 }
02444 
02445 static void set_general_info(HWND hwnd,
02446  PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo)
02447 {
02448     set_cert_info(hwnd, pCertViewInfo);
02449     set_cert_name_string(hwnd, pCertViewInfo->pCertContext, 0,
02450      IDS_SUBJECT_HEADING);
02451     set_cert_name_string(hwnd, pCertViewInfo->pCertContext,
02452      CERT_NAME_ISSUER_FLAG, IDS_ISSUER_HEADING);
02453     set_cert_validity_period(hwnd, pCertViewInfo->pCertContext);
02454 }
02455 
02456 static LRESULT CALLBACK user_notice_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
02457  LPARAM lp)
02458 {
02459     LRESULT ret = 0;
02460     HWND text;
02461     struct IssuerStatement *issuerStatement;
02462 
02463     switch (msg)
02464     {
02465     case WM_INITDIALOG:
02466         text = GetDlgItem(hwnd, IDC_USERNOTICE);
02467         issuerStatement = (struct IssuerStatement *)lp;
02468         add_unformatted_text_to_control(text, issuerStatement->userNotice,
02469          strlenW(issuerStatement->userNotice));
02470         if (issuerStatement->cps)
02471             SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)issuerStatement->cps);
02472         else
02473             EnableWindow(GetDlgItem(hwnd, IDC_CPS), FALSE);
02474         break;
02475     case WM_COMMAND:
02476         switch (wp)
02477         {
02478         case IDOK:
02479             EndDialog(hwnd, IDOK);
02480             ret = TRUE;
02481             break;
02482         case IDC_CPS:
02483         {
02484             IBindCtx *bctx = NULL;
02485             LPWSTR cps;
02486 
02487             CreateBindCtx(0, &bctx);
02488             cps = (LPWSTR)GetWindowLongPtrW(hwnd, DWLP_USER);
02489             HlinkSimpleNavigateToString(cps, NULL, NULL, NULL, bctx, NULL,
02490              HLNF_OPENINNEWWINDOW, 0);
02491             IBindCtx_Release(bctx);
02492             break;
02493         }
02494         }
02495     }
02496     return ret;
02497 }
02498 
02499 static void show_user_notice(HWND hwnd, struct IssuerStatement *issuerStatement)
02500 {
02501     DialogBoxParamW(hInstance, MAKEINTRESOURCEW(IDD_USERNOTICE), hwnd,
02502      user_notice_dlg_proc, (LPARAM)issuerStatement);
02503 }
02504 
02505 static LRESULT CALLBACK general_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
02506  LPARAM lp)
02507 {
02508     PROPSHEETPAGEW *page;
02509     PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo;
02510 
02511     TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd, msg, wp, lp);
02512 
02513     switch (msg)
02514     {
02515     case WM_INITDIALOG:
02516         page = (PROPSHEETPAGEW *)lp;
02517         pCertViewInfo = (PCCRYPTUI_VIEWCERTIFICATE_STRUCTW)page->lParam;
02518         if (pCertViewInfo->dwFlags & CRYPTUI_DISABLE_ADDTOSTORE)
02519             ShowWindow(GetDlgItem(hwnd, IDC_ADDTOSTORE), FALSE);
02520         EnableWindow(GetDlgItem(hwnd, IDC_ISSUERSTATEMENT), FALSE);
02521         set_general_info(hwnd, pCertViewInfo);
02522         break;
02523     case WM_COMMAND:
02524         switch (wp)
02525         {
02526         case IDC_ADDTOSTORE:
02527             CryptUIWizImport(0, hwnd, NULL, NULL, NULL);
02528             break;
02529         case IDC_ISSUERSTATEMENT:
02530         {
02531             struct IssuerStatement *issuerStatement =
02532              (struct IssuerStatement *)GetWindowLongPtrW(hwnd, DWLP_USER);
02533 
02534             if (issuerStatement)
02535             {
02536                 if (issuerStatement->userNotice)
02537                     show_user_notice(hwnd, issuerStatement);
02538                 else if (issuerStatement->cps)
02539                 {
02540                     IBindCtx *bctx = NULL;
02541 
02542                     CreateBindCtx(0, &bctx);
02543                     HlinkSimpleNavigateToString(issuerStatement->cps, NULL,
02544                      NULL, NULL, bctx, NULL, HLNF_OPENINNEWWINDOW, 0);
02545                     IBindCtx_Release(bctx);
02546                 }
02547             }
02548             break;
02549         }
02550         }
02551         break;
02552     }
02553     return 0;
02554 }
02555 
02556 static UINT CALLBACK general_callback_proc(HWND hwnd, UINT msg,
02557  PROPSHEETPAGEW *page)
02558 {
02559     struct IssuerStatement *issuerStatement;
02560 
02561     switch (msg)
02562     {
02563     case PSPCB_RELEASE:
02564         issuerStatement =
02565          (struct IssuerStatement *)GetWindowLongPtrW(hwnd, DWLP_USER);
02566         if (issuerStatement)
02567         {
02568             HeapFree(GetProcessHeap(), 0, issuerStatement->cps);
02569             HeapFree(GetProcessHeap(), 0, issuerStatement->userNotice);
02570             HeapFree(GetProcessHeap(), 0, issuerStatement);
02571         }
02572         break;
02573     }
02574     return 1;
02575 }
02576 
02577 static void init_general_page(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo,
02578  PROPSHEETPAGEW *page)
02579 {
02580     memset(page, 0, sizeof(PROPSHEETPAGEW));
02581     page->dwSize = sizeof(PROPSHEETPAGEW);
02582     page->dwFlags = PSP_USECALLBACK;
02583     page->pfnCallback = general_callback_proc;
02584     page->hInstance = hInstance;
02585     page->u.pszTemplate = MAKEINTRESOURCEW(IDD_GENERAL);
02586     page->pfnDlgProc = general_dlg_proc;
02587     page->lParam = (LPARAM)pCertViewInfo;
02588 }
02589 
02590 typedef WCHAR * (*field_format_func)(PCCERT_CONTEXT cert);
02591 
02592 static WCHAR *field_format_version(PCCERT_CONTEXT cert)
02593 {
02594     static const WCHAR fmt[] = { 'V','%','d',0 };
02595     WCHAR *buf = HeapAlloc(GetProcessHeap(), 0, 12 * sizeof(WCHAR));
02596 
02597     if (buf)
02598         sprintfW(buf, fmt, cert->pCertInfo->dwVersion);
02599     return buf;
02600 }
02601 
02602 static WCHAR *format_hex_string(void *pb, DWORD cb)
02603 {
02604     WCHAR *buf = HeapAlloc(GetProcessHeap(), 0, (cb * 3 + 1) * sizeof(WCHAR));
02605 
02606     if (buf)
02607     {
02608         static const WCHAR fmt[] = { '%','0','2','x',' ',0 };
02609         DWORD i;
02610         WCHAR *ptr;
02611 
02612         for (i = 0, ptr = buf; i < cb; i++, ptr += 3)
02613             sprintfW(ptr, fmt, ((BYTE *)pb)[i]);
02614     }
02615     return buf;
02616 }
02617 
02618 static WCHAR *field_format_serial_number(PCCERT_CONTEXT cert)
02619 {
02620     return format_hex_string(cert->pCertInfo->SerialNumber.pbData,
02621      cert->pCertInfo->SerialNumber.cbData);
02622 }
02623 
02624 static WCHAR *field_format_issuer(PCCERT_CONTEXT cert)
02625 {
02626     return get_cert_name_string(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE,
02627      CERT_NAME_ISSUER_FLAG);
02628 }
02629 
02630 static WCHAR *field_format_detailed_cert_name(PCERT_NAME_BLOB name)
02631 {
02632     WCHAR *str = NULL;
02633     DWORD len = CertNameToStrW(X509_ASN_ENCODING, name,
02634      CERT_X500_NAME_STR | CERT_NAME_STR_CRLF_FLAG, NULL, 0);
02635 
02636     if (len)
02637     {
02638         str = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
02639         if (str)
02640             CertNameToStrW(X509_ASN_ENCODING, name,
02641              CERT_X500_NAME_STR | CERT_NAME_STR_CRLF_FLAG, str, len);
02642     }
02643     return str;
02644 }
02645 
02646 static WCHAR *field_format_detailed_issuer(PCCERT_CONTEXT cert, void *param)
02647 {
02648     return field_format_detailed_cert_name(&cert->pCertInfo->Issuer);
02649 }
02650 
02651 static WCHAR *field_format_subject(PCCERT_CONTEXT cert)
02652 {
02653     return get_cert_name_string(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0);
02654 }
02655 
02656 static WCHAR *field_format_detailed_subject(PCCERT_CONTEXT cert, void *param)
02657 {
02658     return field_format_detailed_cert_name(&cert->pCertInfo->Subject);
02659 }
02660 
02661 static WCHAR *format_long_date(const FILETIME *fileTime)
02662 {
02663     WCHAR dateFmt[80]; /* long enough for LOCALE_SLONGDATE */
02664     DWORD len;
02665     WCHAR *buf = NULL;
02666     SYSTEMTIME sysTime;
02667 
02668     /* FIXME: format isn't quite right, want time too */
02669     GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT, LOCALE_SLONGDATE, dateFmt,
02670      sizeof(dateFmt) / sizeof(dateFmt[0]));
02671     FileTimeToSystemTime(fileTime, &sysTime);
02672     len = GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, NULL, 0);
02673     if (len)
02674     {
02675         buf = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
02676         if (buf)
02677             GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, buf,
02678              len);
02679     }
02680     return buf;
02681 }
02682 
02683 static WCHAR *field_format_from_date(PCCERT_CONTEXT cert)
02684 {
02685     return format_long_date(&cert->pCertInfo->NotBefore);
02686 }
02687 
02688 static WCHAR *field_format_to_date(PCCERT_CONTEXT cert)
02689 {
02690     return format_long_date(&cert->pCertInfo->NotAfter);
02691 }
02692 
02693 static WCHAR *field_format_public_key(PCCERT_CONTEXT cert)
02694 {
02695     PCCRYPT_OID_INFO oidInfo;
02696     WCHAR *buf = NULL;
02697 
02698     oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
02699      cert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId, 0);
02700     if (oidInfo)
02701     {
02702         WCHAR fmt[MAX_STRING_LEN];
02703 
02704         if (LoadStringW(hInstance, IDS_FIELD_PUBLIC_KEY_FORMAT, fmt,
02705          sizeof(fmt) / sizeof(fmt[0])))
02706         {
02707             DWORD len;
02708 
02709             /* Allocate the output buffer.  Use the number of bytes in the
02710              * public key as a conservative (high) estimate for the number of
02711              * digits in its output.
02712              * The output is of the form (in English)
02713              * "<public key algorithm> (<public key bit length> bits)".
02714              * Ordinarily having two positional parameters in a string is not a
02715              * good idea, but as this isn't a sentence fragment, it shouldn't
02716              * be word-order dependent.
02717              */
02718             len = strlenW(fmt) + strlenW(oidInfo->pwszName) +
02719                 cert->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData * 8;
02720             buf = HeapAlloc(GetProcessHeap(), 0, len * sizeof(*buf));
02721             if (buf)
02722             {
02723                 DWORD_PTR args[2];
02724                 args[0] = (DWORD_PTR)oidInfo->pwszName;
02725                 args[1] = CertGetPublicKeyLength(X509_ASN_ENCODING,
02726                               &cert->pCertInfo->SubjectPublicKeyInfo);
02727                 FormatMessageW(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ARGUMENT_ARRAY,
02728                                fmt, 0, 0, buf, len, (__ms_va_list*)args);
02729             }
02730         }
02731     }
02732     return buf;
02733 }
02734 
02735 static WCHAR *field_format_detailed_public_key(PCCERT_CONTEXT cert, void *param)
02736 {
02737     return format_hex_string(
02738      cert->pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData,
02739      cert->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData);
02740 }
02741 
02742 struct field_value_data;
02743 struct detail_data
02744 {
02745     PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo;
02746     BOOL *pfPropertiesChanged;
02747     int cFields;
02748     struct field_value_data *fields;
02749 };
02750 
02751 typedef void (*add_fields_func)(HWND hwnd, struct detail_data *data);
02752 
02753 typedef WCHAR *(*create_detailed_value_func)(PCCERT_CONTEXT cert, void *param);
02754 
02755 struct field_value_data
02756 {
02757     create_detailed_value_func create;
02758     LPWSTR detailed_value;
02759     void *param;
02760 };
02761 
02762 static void add_field_value_data(struct detail_data *data,
02763  create_detailed_value_func create, void *param)
02764 {
02765     if (data->cFields)
02766         data->fields = HeapReAlloc(GetProcessHeap(), 0, data->fields,
02767          (data->cFields + 1) * sizeof(struct field_value_data));
02768     else
02769         data->fields = HeapAlloc(GetProcessHeap(), 0,
02770          sizeof(struct field_value_data));
02771     if (data->fields)
02772     {
02773         data->fields[data->cFields].create = create;
02774         data->fields[data->cFields].detailed_value = NULL;
02775         data->fields[data->cFields].param = param;
02776         data->cFields++;
02777     }
02778 }
02779 
02780 static void add_field_and_value_to_list(HWND hwnd, struct detail_data *data,
02781  LPWSTR field, LPWSTR value, create_detailed_value_func create, void *param)
02782 {
02783     LVITEMW item;
02784     int iItem = SendMessageW(hwnd, LVM_GETITEMCOUNT, 0, 0);
02785 
02786     item.mask = LVIF_TEXT | LVIF_PARAM;
02787     item.iItem = iItem;
02788     item.iSubItem = 0;
02789     item.pszText = field;
02790     item.lParam = (LPARAM)data;
02791     SendMessageW(hwnd, LVM_INSERTITEMW, 0, (LPARAM)&item);
02792     if (value)
02793     {
02794         item.pszText = value;
02795         item.iSubItem = 1;
02796         SendMessageW(hwnd, LVM_SETITEMTEXTW, iItem, (LPARAM)&item);
02797     }
02798     add_field_value_data(data, create, param);
02799 }
02800 
02801 static void add_string_id_and_value_to_list(HWND hwnd, struct detail_data *data,
02802  int id, LPWSTR value, create_detailed_value_func create, void *param)
02803 {
02804     WCHAR buf[MAX_STRING_LEN];
02805 
02806     LoadStringW(hInstance, id, buf, sizeof(buf) / sizeof(buf[0]));
02807     add_field_and_value_to_list(hwnd, data, buf, value, create, param);
02808 }
02809 
02810 struct v1_field
02811 {
02812     int id;
02813     field_format_func format;
02814     create_detailed_value_func create_detailed_value;
02815 };
02816 
02817 static void add_v1_field(HWND hwnd, struct detail_data *data,
02818  const struct v1_field *field)
02819 {
02820     WCHAR *val = field->format(data->pCertViewInfo->pCertContext);
02821 
02822     if (val)
02823     {
02824         add_string_id_and_value_to_list(hwnd, data, field->id, val,
02825          field->create_detailed_value, NULL);
02826         HeapFree(GetProcessHeap(), 0, val);
02827     }
02828 }
02829 
02830 static const struct v1_field v1_fields[] = {
02831  { IDS_FIELD_VERSION, field_format_version, NULL },
02832  { IDS_FIELD_SERIAL_NUMBER, field_format_serial_number, NULL },
02833  { IDS_FIELD_ISSUER, field_format_issuer, field_format_detailed_issuer },
02834  { IDS_FIELD_VALID_FROM, field_format_from_date, NULL },
02835  { IDS_FIELD_VALID_TO, field_format_to_date, NULL },
02836  { IDS_FIELD_SUBJECT, field_format_subject, field_format_detailed_subject },
02837  { IDS_FIELD_PUBLIC_KEY, field_format_public_key,
02838    field_format_detailed_public_key }
02839 };
02840 
02841 static void add_v1_fields(HWND hwnd, struct detail_data *data)
02842 {
02843     int i;
02844     PCCERT_CONTEXT cert = data->pCertViewInfo->pCertContext;
02845 
02846     /* The last item in v1_fields is the public key, which is not in the loop
02847      * because it's a special case.
02848      */
02849     for (i = 0; i < sizeof(v1_fields) / sizeof(v1_fields[0]) - 1; i++)
02850         add_v1_field(hwnd, data, &v1_fields[i]);
02851     if (cert->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData)
02852         add_v1_field(hwnd, data, &v1_fields[i]);
02853 }
02854 
02855 static WCHAR *crypt_format_extension(const CERT_EXTENSION *ext, DWORD formatStrType)
02856 {
02857     WCHAR *str = NULL;
02858     DWORD size;
02859 
02860     if (CryptFormatObject(X509_ASN_ENCODING, 0, formatStrType, NULL,
02861      ext->pszObjId, ext->Value.pbData, ext->Value.cbData, NULL, &size))
02862     {
02863         str = HeapAlloc(GetProcessHeap(), 0, size);
02864         CryptFormatObject(X509_ASN_ENCODING, 0, formatStrType, NULL,
02865          ext->pszObjId, ext->Value.pbData, ext->Value.cbData, str, &size);
02866     }
02867     return str;
02868 }
02869 
02870 static WCHAR *field_format_extension_hex_with_ascii(const CERT_EXTENSION *ext)
02871 {
02872     WCHAR *str = NULL;
02873 
02874     if (ext->Value.cbData)
02875     {
02876         /* The output is formatted as:
02877          * <hex bytes>  <ascii bytes>\n
02878          * where <hex bytes> is a string of up to 8 bytes, output as %02x,
02879          * and <ascii bytes> is the ASCII equivalent of each byte, or '.' if
02880          * the byte is not printable.
02881          * So, for example, the extension value consisting of the following
02882          * bytes:
02883          *   0x30,0x14,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x03,
02884          *   0x13,0x09,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67
02885          * is output as:
02886          *   30 14 31 12 30 10 06 03  0.1.0...
02887          *   55 04 03 13 09 4a 75 61  U....Jua
02888          *   6e 20 4c 61 6e 67        n Lang
02889          * The allocation size therefore requires:
02890          * - 4 characters per character in an 8-byte line
02891          *   (2 for the hex format, one for the space, one for the ASCII value)
02892          * - 3 more characters per 8-byte line (two spaces and a newline)
02893          * - 1 character for the terminating nul
02894          * FIXME: should use a fixed-width font for this
02895          */
02896         DWORD lines = (ext->Value.cbData + 7) / 8;
02897 
02898         str = HeapAlloc(GetProcessHeap(), 0,
02899          (lines * 8 * 4 + lines * 3 + 1) * sizeof(WCHAR));
02900         if (str)
02901         {
02902             static const WCHAR fmt[] = { '%','0','2','x',' ',0 };
02903             DWORD i, j;
02904             WCHAR *ptr;
02905 
02906             for (i = 0, ptr = str; i < ext->Value.cbData; i += 8)
02907             {
02908                 /* Output as hex bytes first */
02909                 for (j = i; j < min(i + 8, ext->Value.cbData); j++, ptr += 3)
02910                     sprintfW(ptr, fmt, ext->Value.pbData[j]);
02911                 /* Pad the hex output with spaces for alignment */
02912                 if (j == ext->Value.cbData && j % 8)
02913                 {
02914                     static const WCHAR pad[] = { ' ',' ',' ' };
02915 
02916                     for (; j % 8; j++, ptr += sizeof(pad) / sizeof(pad[0]))
02917                         memcpy(ptr, pad, sizeof(pad));
02918                 }
02919                 /* The last sprintfW included a space, so just insert one
02920                  * more space between the hex bytes and the ASCII output
02921                  */
02922                 *ptr++ = ' ';
02923                 /* Output as ASCII bytes */
02924                 for (j = i; j < min(i + 8, ext->Value.cbData); j++, ptr++)
02925                 {
02926                     if (isprintW(ext->Value.pbData[j]) &&
02927                      !isspaceW(ext->Value.pbData[j]))
02928                         *ptr = ext->Value.pbData[j];
02929                     else
02930                         *ptr = '.';
02931                 }
02932                 *ptr++ = '\n';
02933             }
02934             *ptr++ = '\0';
02935         }
02936     }
02937     return str;
02938 }
02939 
02940 static WCHAR *field_format_detailed_extension(PCCERT_CONTEXT cert, void *param)
02941 {
02942     PCERT_EXTENSION ext = param;
02943     LPWSTR str = crypt_format_extension(ext,
02944      CRYPT_FORMAT_STR_MULTI_LINE | CRYPT_FORMAT_STR_NO_HEX);
02945 
02946     if (!str)
02947         str = field_format_extension_hex_with_ascii(ext);
02948     return str;
02949 }
02950 
02951 static void add_cert_extension_detail(HWND hwnd, struct detail_data *data,
02952  PCERT_EXTENSION ext)
02953 {
02954     PCCRYPT_OID_INFO oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
02955      ext->pszObjId, 0);
02956     LPWSTR val = crypt_format_extension(ext, 0);
02957 
02958     if (oidInfo)
02959         add_field_and_value_to_list(hwnd, data, (LPWSTR)oidInfo->pwszName,
02960          val, field_format_detailed_extension, ext);
02961     else
02962     {
02963         DWORD len = strlen(ext->pszObjId);
02964         LPWSTR oidW = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
02965 
02966         if (oidW)
02967         {
02968             DWORD i;
02969 
02970             for (i = 0; i <= len; i++)
02971                 oidW[i] = ext->pszObjId[i];
02972             add_field_and_value_to_list(hwnd, data, oidW, val,
02973              field_format_detailed_extension, ext);
02974             HeapFree(GetProcessHeap(), 0, oidW);
02975         }
02976     }
02977     HeapFree(GetProcessHeap(), 0, val);
02978 }
02979 
02980 static void add_all_extensions(HWND hwnd, struct detail_data *data)
02981 {
02982     DWORD i;
02983     PCCERT_CONTEXT cert = data->pCertViewInfo->pCertContext;
02984 
02985     for (i = 0; i < cert->pCertInfo->cExtension; i++)
02986         add_cert_extension_detail(hwnd, data, &cert->pCertInfo->rgExtension[i]);
02987 }
02988 
02989 static void add_critical_extensions(HWND hwnd, struct detail_data *data)
02990 {
02991     DWORD i;
02992     PCCERT_CONTEXT cert = data->pCertViewInfo->pCertContext;
02993 
02994     for (i = 0; i < cert->pCertInfo->cExtension; i++)
02995         if (cert->pCertInfo->rgExtension[i].fCritical)
02996             add_cert_extension_detail(hwnd, data,
02997              &cert->pCertInfo->rgExtension[i]);
02998 }
02999 
03000 typedef WCHAR * (*prop_to_value_func)(void *pb, DWORD cb);
03001 
03002 struct prop_id_to_string_id
03003 {
03004     DWORD prop;
03005     int id;
03006     BOOL prop_is_string;
03007     prop_to_value_func prop_to_value;
03008 };
03009 
03010 static WCHAR *format_enhanced_key_usage_value(void *pb, DWORD cb)
03011 {
03012     CERT_EXTENSION ext;
03013 
03014     ext.pszObjId = (LPSTR)X509_ENHANCED_KEY_USAGE;
03015     ext.fCritical = FALSE;
03016     ext.Value.pbData = pb;
03017     ext.Value.cbData = cb;
03018     return crypt_format_extension(&ext, 0);
03019 }
03020 
03021 /* Logically the access state should also be checked, and IDC_EDITPROPERTIES
03022  * disabled for read-only certificates, but native doesn't appear to do that.
03023  */
03024 static const struct prop_id_to_string_id prop_id_map[] = {
03025  { CERT_HASH_PROP_ID, IDS_PROP_HASH, FALSE, format_hex_string },
03026  { CERT_FRIENDLY_NAME_PROP_ID, IDS_PROP_FRIENDLY_NAME, TRUE, NULL },
03027  { CERT_DESCRIPTION_PROP_ID, IDS_PROP_DESCRIPTION, TRUE, NULL },
03028  { CERT_ENHKEY_USAGE_PROP_ID, IDS_PROP_ENHKEY_USAGE, FALSE,
03029    format_enhanced_key_usage_value },
03030 };
03031 
03032 static void add_properties(HWND hwnd, struct detail_data *data)
03033 {
03034     DWORD i;
03035     PCCERT_CONTEXT cert = data->pCertViewInfo->pCertContext;
03036 
03037     for (i = 0; i < sizeof(prop_id_map) / sizeof(prop_id_map[0]); i++)
03038     {
03039         DWORD cb;
03040 
03041         if (CertGetCertificateContextProperty(cert, prop_id_map[i].prop, NULL,
03042          &cb))
03043         {
03044             BYTE *pb;
03045             WCHAR *val = NULL;
03046 
03047             /* FIXME: MS adds a separate value for the signature hash
03048              * algorithm.
03049              */
03050             pb = HeapAlloc(GetProcessHeap(), 0, cb);
03051             if (pb)
03052             {
03053                 if (CertGetCertificateContextProperty(cert,
03054                  prop_id_map[i].prop, pb, &cb))
03055                 {
03056                     if (prop_id_map[i].prop_is_string)
03057                     {
03058                         val = (LPWSTR)pb;
03059                         /* Don't double-free pb */
03060                         pb = NULL;
03061                     }
03062                     else
03063                         val = prop_id_map[i].prop_to_value(pb, cb);
03064                 }
03065                 HeapFree(GetProcessHeap(), 0, pb);
03066             }
03067             add_string_id_and_value_to_list(hwnd, data, prop_id_map[i].id, val,
03068              NULL, NULL);
03069         }
03070     }
03071 }
03072 
03073 static void add_all_fields(HWND hwnd, struct detail_data *data)
03074 {
03075     add_v1_fields(hwnd, data);
03076     add_all_extensions(hwnd, data);
03077     add_properties(hwnd, data);
03078 }
03079 
03080 struct selection_list_item
03081 {
03082     int id;
03083     add_fields_func add;
03084 };
03085 
03086 static const struct selection_list_item listItems[] = {
03087  { IDS_FIELDS_ALL, add_all_fields },
03088  { IDS_FIELDS_V1, add_v1_fields },
03089  { IDS_FIELDS_EXTENSIONS, add_all_extensions },
03090  { IDS_FIELDS_CRITICAL_EXTENSIONS, add_critical_extensions },
03091  { IDS_FIELDS_PROPERTIES, add_properties },
03092 };
03093 
03094 static void create_show_list(HWND hwnd, struct detail_data *data)
03095 {
03096     HWND cb = GetDlgItem(hwnd, IDC_DETAIL_SELECT);
03097     WCHAR buf[MAX_STRING_LEN];
03098     int i;
03099 
03100     for (i = 0; i < sizeof(listItems) / sizeof(listItems[0]); i++)
03101     {
03102         int index;
03103 
03104         LoadStringW(hInstance, listItems[i].id, buf,
03105          sizeof(buf) / sizeof(buf[0]));
03106         index = SendMessageW(cb, CB_INSERTSTRING, -1, (LPARAM)buf);
03107         SendMessageW(cb, CB_SETITEMDATA, index, (LPARAM)data);
03108     }
03109     SendMessageW(cb, CB_SETCURSEL, 0, 0);
03110 }
03111 
03112 static void create_listview_columns(HWND hwnd)
03113 {
03114     HWND lv = GetDlgItem(hwnd, IDC_DETAIL_LIST);
03115     RECT rc;
03116     WCHAR buf[MAX_STRING_LEN];
03117     LVCOLUMNW column;
03118 
03119     SendMessageW(lv, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
03120     GetWindowRect(lv, &rc);
03121     LoadStringW(hInstance, IDS_FIELD, buf, sizeof(buf) / sizeof(buf[0]));
03122     column.mask = LVCF_WIDTH | LVCF_TEXT;
03123     column.cx = (rc.right - rc.left) / 2 - 2;
03124     column.pszText = buf;
03125     SendMessageW(lv, LVM_INSERTCOLUMNW, 0, (LPARAM)&column);
03126     LoadStringW(hInstance, IDS_VALUE, buf, sizeof(buf) / sizeof(buf[0]));
03127     SendMessageW(lv, LVM_INSERTCOLUMNW, 1, (LPARAM)&column);
03128 }
03129 
03130 static void set_fields_selection(HWND hwnd, struct detail_data *data, int sel)
03131 {
03132     HWND list = GetDlgItem(hwnd, IDC_DETAIL_LIST);
03133 
03134     if (sel >= 0 && sel < sizeof(listItems) / sizeof(listItems[0]))
03135     {
03136         SendMessageW(list, LVM_DELETEALLITEMS, 0, 0);
03137         listItems[sel].add(list, data);
03138     }
03139 }
03140 
03141 static void create_cert_details_list(HWND hwnd, struct detail_data *data)
03142 {
03143     create_show_list(hwnd, data);
03144     create_listview_columns(hwnd);
03145     set_fields_selection(hwnd, data, 0);
03146 }
03147 
03148 static void add_purpose(HWND hwnd, LPCSTR oid)
03149 {
03150     HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
03151     PCRYPT_OID_INFO info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
03152      sizeof(CRYPT_OID_INFO));
03153 
03154     if (info)
03155     {
03156         char *oidCopy = HeapAlloc(GetProcessHeap(), 0, strlen(oid) + 1);
03157 
03158         if (oidCopy)
03159         {
03160             LVITEMA item;
03161 
03162             strcpy(oidCopy, oid);
03163             info->cbSize = sizeof(CRYPT_OID_INFO);
03164             info->pszOID = oidCopy;
03165             item.mask = LVIF_TEXT | LVIF_STATE | LVIF_PARAM;
03166             item.state = INDEXTOSTATEIMAGEMASK(CheckBitmapIndexChecked);
03167             item.stateMask = LVIS_STATEIMAGEMASK;
03168             item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
03169             item.iSubItem = 0;
03170             item.lParam = (LPARAM)info;
03171             item.pszText = oidCopy;
03172             SendMessageA(lv, LVM_INSERTITEMA, 0, (LPARAM)&item);
03173         }
03174         else
03175             HeapFree(GetProcessHeap(), 0, info);
03176     }
03177 }
03178 
03179 static BOOL is_valid_oid(LPCSTR oid)
03180 {
03181     BOOL ret;
03182 
03183     if (oid[0] != '0' && oid[0] != '1' && oid[0] != '2')
03184         ret = FALSE;
03185     else if (oid[1] != '.')
03186         ret = FALSE;
03187     else if (!oid[2])
03188         ret = FALSE;
03189     else
03190     {
03191         const char *ptr;
03192         BOOL expectNum = TRUE;
03193 
03194         for (ptr = oid + 2, ret = TRUE; ret && *ptr; ptr++)
03195         {
03196             if (expectNum)
03197             {
03198                 if (!isdigit(*ptr))
03199                     ret = FALSE;
03200                 else if (*(ptr + 1) == '.')
03201                     expectNum = FALSE;
03202             }
03203             else
03204             {
03205                 if (*ptr != '.')
03206                     ret = FALSE;
03207                 else if (!(*(ptr + 1)))
03208                     ret = FALSE;
03209                 else
03210                     expectNum = TRUE;
03211             }
03212         }
03213     }
03214     return ret;
03215 }
03216 
03217 static BOOL is_oid_in_list(HWND hwnd, LPCSTR oid)
03218 {
03219     return find_oid_in_list(GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES), oid)
03220      != -1;
03221 }
03222 
03223 #define MAX_PURPOSE 255
03224 
03225 static LRESULT CALLBACK add_purpose_dlg_proc(HWND hwnd, UINT msg,
03226  WPARAM wp, LPARAM lp)
03227 {
03228     LRESULT ret = 0;
03229     char buf[MAX_PURPOSE + 1];
03230 
03231     switch (msg)
03232     {
03233     case WM_INITDIALOG:
03234         SendMessageW(GetDlgItem(hwnd, IDC_NEW_PURPOSE), EM_SETLIMITTEXT,
03235          MAX_PURPOSE, 0);
03236         ShowScrollBar(GetDlgItem(hwnd, IDC_NEW_PURPOSE), SB_VERT, FALSE);
03237         SetWindowLongPtrW(hwnd, DWLP_USER, lp);
03238         break;
03239     case WM_COMMAND:
03240         switch (HIWORD(wp))
03241         {
03242         case EN_CHANGE:
03243             if (LOWORD(wp) == IDC_NEW_PURPOSE)
03244             {
03245                 /* Show/hide scroll bar on description depending on how much
03246                  * text it has.
03247                  */
03248                 HWND description = GetDlgItem(hwnd, IDC_NEW_PURPOSE);
03249                 int lines = SendMessageW(description, EM_GETLINECOUNT, 0, 0);
03250 
03251                 ShowScrollBar(description, SB_VERT, lines > 1);
03252             }
03253             break;
03254         case BN_CLICKED:
03255             switch (LOWORD(wp))
03256             {
03257             case IDOK:
03258                 SendMessageA(GetDlgItem(hwnd, IDC_NEW_PURPOSE), WM_GETTEXT,
03259                  sizeof(buf) / sizeof(buf[0]), (LPARAM)buf);
03260                 if (!buf[0])
03261                 {
03262                     /* An empty purpose is the same as cancelling */
03263                     EndDialog(hwnd, IDCANCEL);
03264                     ret = TRUE;
03265                 }
03266                 else if (!is_valid_oid(buf))
03267                 {
03268                     WCHAR title[MAX_STRING_LEN], error[MAX_STRING_LEN];
03269 
03270                     LoadStringW(hInstance, IDS_CERTIFICATE_PURPOSE_ERROR, error,
03271                      sizeof(error) / sizeof(error[0]));
03272                     LoadStringW(hInstance, IDS_CERTIFICATE_PROPERTIES, title,
03273                      sizeof(title) / sizeof(title[0]));
03274                     MessageBoxW(hwnd, error, title, MB_ICONERROR | MB_OK);
03275                 }
03276                 else if (is_oid_in_list(
03277                  (HWND)GetWindowLongPtrW(hwnd, DWLP_USER), buf))
03278                 {
03279                     WCHAR title[MAX_STRING_LEN], error[MAX_STRING_LEN];
03280 
03281                     LoadStringW(hInstance, IDS_CERTIFICATE_PURPOSE_EXISTS,
03282                      error, sizeof(error) / sizeof(error[0]));
03283                     LoadStringW(hInstance, IDS_CERTIFICATE_PROPERTIES, title,
03284                      sizeof(title) / sizeof(title[0]));
03285                     MessageBoxW(hwnd, error, title, MB_ICONEXCLAMATION | MB_OK);
03286                 }
03287                 else
03288                 {
03289                     HWND parent = (HWND)GetWindowLongPtrW(hwnd, DWLP_USER);
03290 
03291                     add_purpose(parent, buf);
03292                     EndDialog(hwnd, wp);
03293                     ret = TRUE;
03294                 }
03295                 break;
03296             case IDCANCEL:
03297                 EndDialog(hwnd, wp);
03298                 ret = TRUE;
03299                 break;
03300             }
03301             break;
03302         }
03303         break;
03304     }
03305     return ret;
03306 }
03307 
03308 static WCHAR *get_cert_property_as_string(PCCERT_CONTEXT cert, DWORD prop)
03309 {
03310     WCHAR *name = NULL;
03311     DWORD cb;
03312 
03313     if (CertGetCertificateContextProperty(cert, prop, NULL, &cb))
03314     {
03315         name = HeapAlloc(GetProcessHeap(), 0, cb);
03316         if (name)
03317         {
03318             if (!CertGetCertificateContextProperty(cert, prop, name, &cb))
03319             {
03320                 HeapFree(GetProcessHeap(), 0, name);
03321                 name = NULL;
03322             }
03323         }
03324     }
03325     return name;
03326 }
03327 
03328 static void redraw_states(HWND list, BOOL enabled)
03329 {
03330     int items = SendMessageW(list, LVM_GETITEMCOUNT, 0, 0), i;
03331 
03332     for (i = 0; i < items; i++)
03333     {
03334         BOOL change = FALSE;
03335         int state;
03336 
03337         state = SendMessageW(list, LVM_GETITEMSTATE, i, LVIS_STATEIMAGEMASK);
03338         /* This reverses the INDEXTOSTATEIMAGEMASK shift.  There doesn't appear
03339          * to be a handy macro for it.
03340          */
03341         state >>= 12;
03342         if (enabled)
03343         {
03344             if (state == CheckBitmapIndexDisabledChecked)
03345             {
03346                 state = CheckBitmapIndexChecked;
03347                 change = TRUE;
03348             }
03349             if (state == CheckBitmapIndexDisabledUnchecked)
03350             {
03351                 state = CheckBitmapIndexUnchecked;
03352                 change = TRUE;
03353             }
03354         }
03355         else
03356         {
03357             if (state == CheckBitmapIndexChecked)
03358             {
03359                 state = CheckBitmapIndexDisabledChecked;
03360                 change = TRUE;
03361             }
03362             if (state == CheckBitmapIndexUnchecked)
03363             {
03364                 state = CheckBitmapIndexDisabledUnchecked;
03365                 change = TRUE;
03366             }
03367         }
03368         if (change)
03369         {
03370             LVITEMW item;
03371 
03372             item.state = INDEXTOSTATEIMAGEMASK(state);
03373             item.stateMask = LVIS_STATEIMAGEMASK;
03374             SendMessageW(list, LVM_SETITEMSTATE, i, (LPARAM)&item);
03375         }
03376     }
03377 }
03378 
03379 typedef enum {
03380     PurposeEnableAll = 0,
03381     PurposeDisableAll,
03382     PurposeEnableSelected
03383 } PurposeSelection;
03384 
03385 static void select_purposes(HWND hwnd, PurposeSelection selection)
03386 {
03387     HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
03388 
03389     switch (selection)
03390     {
03391     case PurposeEnableAll:
03392     case PurposeDisableAll:
03393         EnableWindow(lv, FALSE);
03394         redraw_states(lv, FALSE);
03395         EnableWindow(GetDlgItem(hwnd, IDC_ADD_PURPOSE), FALSE);
03396         break;
03397     case PurposeEnableSelected:
03398         EnableWindow(lv, TRUE);
03399         redraw_states(lv, TRUE);
03400         EnableWindow(GetDlgItem(hwnd, IDC_ADD_PURPOSE), TRUE);
03401     }
03402 }
03403 
03404 struct edit_cert_data
03405 {
03406     PCCERT_CONTEXT cert;
03407     BOOL *pfPropertiesChanged;
03408     HIMAGELIST imageList;
03409 };
03410 
03411 static void show_cert_usages(HWND hwnd, struct edit_cert_data *data)
03412 {
03413     PCCERT_CONTEXT cert = data->cert;
03414     HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
03415     PCERT_ENHKEY_USAGE usage;
03416     DWORD size;
03417     RECT rc;
03418     LVCOLUMNW column;
03419     PurposeSelection purposeSelection = PurposeEnableAll;
03420 
03421     GetWindowRect(lv, &rc);
03422     column.mask = LVCF_WIDTH;
03423     column.cx = rc.right - rc.left;
03424     SendMessageW(lv, LVM_INSERTCOLUMNW, 0, (LPARAM)&column);
03425     SendMessageW(lv, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)data->imageList);
03426 
03427     /* Get enhanced key usage.  Have to check for a property and an extension
03428      * separately, because CertGetEnhancedKeyUsage will succeed and return an
03429      * empty usage if neither is set.  Unfortunately an empty usage implies
03430      * no usage is allowed, so we have to distinguish between the two cases.
03431      */
03432     if (CertGetEnhancedKeyUsage(cert, CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG,
03433      NULL, &size))
03434     {
03435         usage = HeapAlloc(GetProcessHeap(), 0, size);
03436         if (!CertGetEnhancedKeyUsage(cert,
03437          CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, usage, &size))
03438         {
03439             HeapFree(GetProcessHeap(), 0, usage);
03440             usage = NULL;
03441         }
03442         else if (usage->cUsageIdentifier)
03443             purposeSelection = PurposeEnableSelected;
03444         else
03445             purposeSelection = PurposeDisableAll;
03446     }
03447     else if (CertGetEnhancedKeyUsage(cert, CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG,
03448      NULL, &size))
03449     {
03450         usage = HeapAlloc(GetProcessHeap(), 0, size);
03451         if (!CertGetEnhancedKeyUsage(cert,
03452          CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, usage, &size))
03453         {
03454             HeapFree(GetProcessHeap(), 0, usage);
03455             usage = NULL;
03456         }
03457         else if (usage->cUsageIdentifier)
03458             purposeSelection = PurposeEnableAll;
03459         else
03460             purposeSelection = PurposeDisableAll;
03461     }
03462     else
03463     {
03464         purposeSelection = PurposeEnableAll;
03465         usage = NULL;
03466     }
03467     if (usage)
03468     {
03469         DWORD i;
03470 
03471         for (i = 0; i < usage->cUsageIdentifier; i++)
03472         {
03473             PCCRYPT_OID_INFO info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
03474              usage->rgpszUsageIdentifier[i], CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
03475 
03476             if (info)
03477                 add_known_usage(lv, info, CheckBitmapIndexDisabledChecked);
03478             else
03479                 add_purpose(hwnd, usage->rgpszUsageIdentifier[i]);
03480         }
03481         HeapFree(GetProcessHeap(), 0, usage);
03482     }
03483     else
03484         add_known_usages_to_list(lv, CheckBitmapIndexDisabledChecked);
03485     select_purposes(hwnd, purposeSelection);
03486     SendMessageW(GetDlgItem(hwnd, IDC_ENABLE_ALL_PURPOSES + purposeSelection),
03487      BM_CLICK, 0, 0);
03488 }
03489 
03490 static void set_general_cert_properties(HWND hwnd, struct edit_cert_data *data)
03491 {
03492     PCCERT_CONTEXT cert = data->cert;
03493     WCHAR *str;
03494 
03495     if ((str = get_cert_property_as_string(cert, CERT_FRIENDLY_NAME_PROP_ID)))
03496     {
03497         SendMessageW(GetDlgItem(hwnd, IDC_FRIENDLY_NAME), WM_SETTEXT, 0,
03498          (LPARAM)str);
03499         HeapFree(GetProcessHeap(), 0, str);
03500     }
03501     if ((str = get_cert_property_as_string(cert, CERT_DESCRIPTION_PROP_ID)))
03502     {
03503         SendMessageW(GetDlgItem(hwnd, IDC_DESCRIPTION), WM_SETTEXT, 0,
03504          (LPARAM)str);
03505         HeapFree(GetProcessHeap(), 0, str);
03506     }
03507     show_cert_usages(hwnd, data);
03508 }
03509 
03510 static void set_cert_string_property(PCCERT_CONTEXT cert, DWORD prop,
03511  LPWSTR str)
03512 {
03513     if (str && strlenW(str))
03514     {
03515         CRYPT_DATA_BLOB blob;
03516 
03517         blob.pbData = (BYTE *)str;
03518         blob.cbData = (strlenW(str) + 1) * sizeof(WCHAR);
03519         CertSetCertificateContextProperty(cert, prop, 0, &blob);
03520     }
03521     else
03522         CertSetCertificateContextProperty(cert, prop, 0, NULL);
03523 }
03524 
03525 #define WM_REFRESH_VIEW WM_USER + 0
03526 
03527 static BOOL CALLBACK refresh_propsheet_pages(HWND hwnd, LPARAM lParam)
03528 {
03529     if ((GetClassLongW(hwnd, GCW_ATOM) == WC_DIALOG))
03530         SendMessageW(hwnd, WM_REFRESH_VIEW, 0, 0);
03531     return TRUE;
03532 }
03533 
03534 #define MAX_FRIENDLY_NAME 40
03535 #define MAX_DESCRIPTION 255
03536 
03537 static void apply_general_changes(HWND hwnd)
03538 {
03539     WCHAR buf[MAX_DESCRIPTION + 1];
03540     struct edit_cert_data *data =
03541      (struct edit_cert_data *)GetWindowLongPtrW(hwnd, DWLP_USER);
03542 
03543     SendMessageW(GetDlgItem(hwnd, IDC_FRIENDLY_NAME), WM_GETTEXT,
03544      sizeof(buf) / sizeof(buf[0]), (LPARAM)buf);
03545     set_cert_string_property(data->cert, CERT_FRIENDLY_NAME_PROP_ID, buf);
03546     SendMessageW(GetDlgItem(hwnd, IDC_DESCRIPTION), WM_GETTEXT,
03547      sizeof(buf) / sizeof(buf[0]), (LPARAM)buf);
03548     set_cert_string_property(data->cert, CERT_DESCRIPTION_PROP_ID, buf);
03549     if (IsDlgButtonChecked(hwnd, IDC_ENABLE_ALL_PURPOSES))
03550     {
03551         /* Setting a NULL usage removes the enhanced key usage property. */
03552         CertSetEnhancedKeyUsage(data->cert, NULL);
03553     }
03554     else if (IsDlgButtonChecked(hwnd, IDC_DISABLE_ALL_PURPOSES))
03555     {
03556         CERT_ENHKEY_USAGE usage = { 0, NULL };
03557 
03558         CertSetEnhancedKeyUsage(data->cert, &usage);
03559     }
03560     else if (IsDlgButtonChecked(hwnd, IDC_ENABLE_SELECTED_PURPOSES))
03561     {
03562         HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
03563         CERT_ENHKEY_USAGE usage = { 0, NULL };
03564         int purposes = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0), i;
03565         LVITEMW item;
03566 
03567         item.mask = LVIF_STATE | LVIF_PARAM;
03568         item.iSubItem = 0;
03569         item.stateMask = LVIS_STATEIMAGEMASK;
03570         for (i = 0; i < purposes; i++)
03571         {
03572             item.iItem = i;
03573             if (SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item))
03574             {
03575                 int state = item.state >> 12;
03576 
03577                 if (state == CheckBitmapIndexChecked)
03578                 {
03579                     CRYPT_OID_INFO *info = (CRYPT_OID_INFO *)item.lParam;
03580 
03581                     if (usage.cUsageIdentifier)
03582                         usage.rgpszUsageIdentifier =
03583                          HeapReAlloc(GetProcessHeap(), 0,
03584                          usage.rgpszUsageIdentifier,
03585                          (usage.cUsageIdentifier + 1) * sizeof(LPSTR));
03586                     else
03587                         usage.rgpszUsageIdentifier =
03588                          HeapAlloc(GetProcessHeap(), 0, sizeof(LPSTR));
03589                     if (usage.rgpszUsageIdentifier)
03590                         usage.rgpszUsageIdentifier[usage.cUsageIdentifier++] =
03591                          (LPSTR)info->pszOID;
03592                 }
03593             }
03594         }
03595         CertSetEnhancedKeyUsage(data->cert, &usage);
03596         HeapFree(GetProcessHeap(), 0, usage.rgpszUsageIdentifier);
03597     }
03598     EnumChildWindows(GetParent(GetParent(hwnd)), refresh_propsheet_pages, 0);
03599     if (data->pfPropertiesChanged)
03600         *data->pfPropertiesChanged = TRUE;
03601 }
03602 
03603 static LRESULT CALLBACK cert_properties_general_dlg_proc(HWND hwnd, UINT msg,
03604  WPARAM wp, LPARAM lp)
03605 {
03606     PROPSHEETPAGEW *page;
03607 
03608     TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd, msg, wp, lp);
03609 
03610     switch (msg)
03611     {
03612     case WM_INITDIALOG:
03613     {
03614         HWND description = GetDlgItem(hwnd, IDC_DESCRIPTION);
03615         struct detail_data *detailData;
03616         struct edit_cert_data *editData;
03617 
03618         page = (PROPSHEETPAGEW *)lp;
03619         detailData = (struct detail_data *)page->lParam;
03620         SendMessageW(GetDlgItem(hwnd, IDC_FRIENDLY_NAME), EM_SETLIMITTEXT,
03621          MAX_FRIENDLY_NAME, 0);
03622         SendMessageW(description, EM_SETLIMITTEXT, MAX_DESCRIPTION, 0);
03623         ShowScrollBar(description, SB_VERT, FALSE);
03624         editData = HeapAlloc(GetProcessHeap(), 0,
03625          sizeof(struct edit_cert_data));
03626         if (editData)
03627         {
03628             editData->imageList = ImageList_Create(16, 16,
03629              ILC_COLOR4 | ILC_MASK, 4, 0);
03630             if (editData->imageList)
03631             {
03632                 HBITMAP bmp;
03633                 COLORREF backColor = RGB(255, 0, 255);
03634 
03635                 bmp = LoadBitmapW(hInstance, MAKEINTRESOURCEW(IDB_CHECKS));
03636                 ImageList_AddMasked(editData->imageList, bmp, backColor);
03637                 DeleteObject(bmp);
03638                 ImageList_SetBkColor(editData->imageList, CLR_NONE);
03639             }
03640             editData->cert = detailData->pCertViewInfo->pCertContext;
03641             editData->pfPropertiesChanged = detailData->pfPropertiesChanged;
03642             SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)editData);
03643             set_general_cert_properties(hwnd, editData);
03644         }
03645         break;
03646     }
03647     case WM_NOTIFY:
03648     {
03649         NMHDR *hdr = (NMHDR *)lp;
03650         NMITEMACTIVATE *nm;
03651 
03652         switch (hdr->code)
03653         {
03654         case NM_CLICK:
03655             nm = (NMITEMACTIVATE *)lp;
03656             toggle_usage(hwnd, nm->iItem);
03657             SendMessageW(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0);
03658             break;
03659         case PSN_APPLY:
03660             apply_general_changes(hwnd);
03661             break;
03662         }
03663         break;
03664     }
03665     case WM_COMMAND:
03666         switch (HIWORD(wp))
03667         {
03668         case EN_CHANGE:
03669             SendMessageW(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0);
03670             if (LOWORD(wp) == IDC_DESCRIPTION)
03671             {
03672                 /* Show/hide scroll bar on description depending on how much
03673                  * text it has.
03674                  */
03675                 HWND description = GetDlgItem(hwnd, IDC_DESCRIPTION);
03676                 int lines = SendMessageW(description, EM_GETLINECOUNT, 0, 0);
03677 
03678                 ShowScrollBar(description, SB_VERT, lines > 1);
03679             }
03680             break;
03681         case BN_CLICKED:
03682             switch (LOWORD(wp))
03683             {
03684             case IDC_ADD_PURPOSE:
03685                 if (DialogBoxParamW(hInstance,
03686                  MAKEINTRESOURCEW(IDD_ADD_CERT_PURPOSE), hwnd,
03687                  add_purpose_dlg_proc, (LPARAM)hwnd) == IDOK)
03688                     SendMessageW(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0);
03689                 break;
03690             case IDC_ENABLE_ALL_PURPOSES:
03691             case IDC_DISABLE_ALL_PURPOSES:
03692             case IDC_ENABLE_SELECTED_PURPOSES:
03693                 SendMessageW(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0);
03694                 select_purposes(hwnd, LOWORD(wp) - IDC_ENABLE_ALL_PURPOSES);
03695                 break;
03696             }
03697             break;
03698         }
03699         break;
03700     }
03701     return 0;
03702 }
03703 
03704 static UINT CALLBACK cert_properties_general_callback(HWND hwnd, UINT msg,
03705  PROPSHEETPAGEW *page)
03706 {
03707     HWND lv;
03708     int cItem, i;
03709     struct edit_cert_data *data;
03710 
03711     switch (msg)
03712     {
03713     case PSPCB_RELEASE:
03714         lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
03715         cItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
03716         for (i = 0; i < cItem; i++)
03717         {
03718             LVITEMW item;
03719 
03720             item.mask = LVIF_PARAM;
03721             item.iItem = i;
03722             item.iSubItem = 0;
03723             if (SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item) && item.lParam)
03724             {
03725                 PCRYPT_OID_INFO info = (PCRYPT_OID_INFO)item.lParam;
03726 
03727                 if (info->cbSize == sizeof(CRYPT_OID_INFO) && !info->dwGroupId)
03728                 {
03729                     HeapFree(GetProcessHeap(), 0, (LPSTR)info->pszOID);
03730                     HeapFree(GetProcessHeap(), 0, info);
03731                 }
03732             }
03733         }
03734         data = (struct edit_cert_data *)GetWindowLongPtrW(hwnd, DWLP_USER);
03735         if (data)
03736         {
03737             ImageList_Destroy(data->imageList);
03738             HeapFree(GetProcessHeap(), 0, data);
03739         }
03740         break;
03741     }
03742     return 1;
03743 }
03744 
03745 static void show_edit_cert_properties_dialog(HWND parent,
03746  struct detail_data *data)
03747 {
03748     PROPSHEETHEADERW hdr;
03749     PROPSHEETPAGEW page; /* FIXME: need to add a cross-certificate page */
03750 
03751     TRACE("(%p)\n", data);
03752 
03753     memset(&page, 0, sizeof(PROPSHEETPAGEW));
03754     page.dwSize = sizeof(page);
03755     page.dwFlags = PSP_USECALLBACK;
03756     page.pfnCallback = cert_properties_general_callback;
03757     page.hInstance = hInstance;
03758     page.u.pszTemplate = MAKEINTRESOURCEW(IDD_CERT_PROPERTIES_GENERAL);
03759     page.pfnDlgProc = cert_properties_general_dlg_proc;
03760     page.lParam = (LPARAM)data;
03761 
03762     memset(&hdr, 0, sizeof(hdr));
03763     hdr.dwSize = sizeof(hdr);
03764     hdr.hwndParent = parent;
03765     hdr.dwFlags = PSH_PROPSHEETPAGE;
03766     hdr.hInstance = hInstance;
03767     hdr.pszCaption = MAKEINTRESOURCEW(IDS_CERTIFICATE_PROPERTIES);
03768     hdr.u3.ppsp = &page;
03769     hdr.nPages = 1;
03770     PropertySheetW(&hdr);
03771 }
03772 
03773 static void free_detail_fields(struct detail_data *data)
03774 {
03775     DWORD i;
03776 
03777     for (i = 0; i < data->cFields; i++)
03778         HeapFree(GetProcessHeap(), 0, data->fields[i].detailed_value);
03779     HeapFree(GetProcessHeap(), 0, data->fields);
03780     data->fields = NULL;
03781     data->cFields = 0;
03782 }
03783 
03784 static void refresh_details_view(HWND hwnd)
03785 {
03786     HWND cb = GetDlgItem(hwnd, IDC_DETAIL_SELECT);
03787     int curSel;
03788     struct detail_data *data;
03789 
03790     curSel = SendMessageW(cb, CB_GETCURSEL, 0, 0);
03791     /* Actually, any index will do, since they all store the same data value */
03792     data = (struct detail_data *)SendMessageW(cb, CB_GETITEMDATA, curSel, 0);
03793     free_detail_fields(data);
03794     set_fields_selection(hwnd, data, curSel);
03795 }
03796 
03797 static LRESULT CALLBACK detail_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
03798  LPARAM lp)
03799 {
03800     PROPSHEETPAGEW *page;
03801     struct detail_data *data;
03802 
03803     TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd, msg, wp, lp);
03804 
03805     switch (msg)
03806     {
03807     case WM_INITDIALOG:
03808         page = (PROPSHEETPAGEW *)lp;
03809         data = (struct detail_data *)page->lParam;
03810         create_cert_details_list(hwnd, data);
03811         if (!(data->pCertViewInfo->dwFlags & CRYPTUI_ENABLE_EDITPROPERTIES))
03812             EnableWindow(GetDlgItem(hwnd, IDC_EDITPROPERTIES), FALSE);
03813         if (data->pCertViewInfo->dwFlags & CRYPTUI_DISABLE_EXPORT)
03814             EnableWindow(GetDlgItem(hwnd, IDC_EXPORT), FALSE);
03815         break;
03816     case WM_NOTIFY:
03817     {
03818         NMITEMACTIVATE *nm;
03819         HWND list = GetDlgItem(hwnd, IDC_DETAIL_LIST);
03820 
03821         nm = (NMITEMACTIVATE*)lp;
03822         if (nm->hdr.hwndFrom == list && nm->uNewState & LVN_ITEMACTIVATE
03823          && nm->hdr.code == LVN_ITEMCHANGED)
03824         {
03825             data = (struct detail_data *)nm->lParam;
03826             if (nm->iItem >= 0 && data && nm->iItem < data->cFields)
03827             {
03828                 WCHAR buf[MAX_STRING_LEN], *val = NULL;
03829                 HWND valueCtl = GetDlgItem(hwnd, IDC_DETAIL_VALUE);
03830 
03831                 if (data->fields[nm->iItem].create)
03832                     val = data->fields[nm->iItem].create(
03833                      data->pCertViewInfo->pCertContext,
03834                      data->fields[nm->iItem].param);
03835                 else
03836                 {
03837                     LVITEMW item;
03838                     int res;
03839 
03840                     item.cchTextMax = sizeof(buf) / sizeof(buf[0]);
03841                     item.mask = LVIF_TEXT;
03842                     item.pszText = buf;
03843                     item.iItem = nm->iItem;
03844                     item.iSubItem = 1;
03845                     res = SendMessageW(list, LVM_GETITEMW, 0, (LPARAM)&item);
03846                     if (res)
03847                         val = buf;
03848                 }
03849                 /* Select all the text in the control, the next update will
03850                  * replace it
03851                  */
03852                 SendMessageW(valueCtl, EM_SETSEL, 0, -1);
03853                 add_unformatted_text_to_control(valueCtl, val,
03854                  val ? strlenW(val) : 0);
03855                 if (val != buf)
03856                     HeapFree(GetProcessHeap(), 0, val);
03857             }
03858         }
03859         break;
03860     }
03861     case WM_COMMAND:
03862         switch (wp)
03863         {
03864         case IDC_EXPORT:
03865         {
03866             HWND cb = GetDlgItem(hwnd, IDC_DETAIL_SELECT);
03867             CRYPTUI_WIZ_EXPORT_INFO info;
03868 
03869             data = (struct detail_data *)SendMessageW(cb, CB_GETITEMDATA, 0, 0);
03870             info.dwSize = sizeof(info);
03871             info.pwszExportFileName = NULL;
03872             info.dwSubjectChoice = CRYPTUI_WIZ_EXPORT_CERT_CONTEXT;
03873             info.u.pCertContext = data->pCertViewInfo->pCertContext;
03874             info.cStores = 0;
03875             CryptUIWizExport(0, hwnd, NULL, &info, NULL);
03876             break;
03877         }
03878         case IDC_EDITPROPERTIES:
03879         {
03880             HWND cb = GetDlgItem(hwnd, IDC_DETAIL_SELECT);
03881             int curSel;
03882 
03883             curSel = SendMessageW(cb, CB_GETCURSEL, 0, 0);
03884             /* Actually, any index will do, since they all store the same
03885              * data value
03886              */
03887             data = (struct detail_data *)SendMessageW(cb, CB_GETITEMDATA,
03888              curSel, 0);
03889             show_edit_cert_properties_dialog(GetParent(hwnd), data);
03890             break;
03891         }
03892         case ((CBN_SELCHANGE << 16) | IDC_DETAIL_SELECT):
03893             refresh_details_view(hwnd);
03894             break;
03895         }
03896         break;
03897     case WM_REFRESH_VIEW:
03898         refresh_details_view(hwnd);
03899         break;
03900     }
03901     return 0;
03902 }
03903 
03904 static UINT CALLBACK detail_callback(HWND hwnd, UINT msg,
03905  PROPSHEETPAGEW *page)
03906 {
03907     struct detail_data *data;
03908 
03909     switch (msg)
03910     {
03911     case PSPCB_RELEASE:
03912         data = (struct detail_data *)page->lParam;
03913         free_detail_fields(data);
03914         HeapFree(GetProcessHeap(), 0, data);
03915         break;
03916     }
03917     return 0;
03918 }
03919 
03920 static BOOL init_detail_page(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo,
03921  BOOL *pfPropertiesChanged, PROPSHEETPAGEW *page)
03922 {
03923     BOOL ret;
03924     struct detail_data *data = HeapAlloc(GetProcessHeap(), 0,
03925      sizeof(struct detail_data));
03926 
03927     if (data)
03928     {
03929         data->pCertViewInfo = pCertViewInfo;
03930         data->pfPropertiesChanged = pfPropertiesChanged;
03931         data->cFields = 0;
03932         data->fields = NULL;
03933         memset(page, 0, sizeof(PROPSHEETPAGEW));
03934         page->dwSize = sizeof(PROPSHEETPAGEW);
03935         page->dwFlags = PSP_USECALLBACK;
03936         page->pfnCallback = detail_callback;
03937         page->hInstance = hInstance;
03938         page->u.pszTemplate = MAKEINTRESOURCEW(IDD_DETAIL);
03939         page->pfnDlgProc = detail_dlg_proc;
03940         page->lParam = (LPARAM)data;
03941         ret = TRUE;
03942     }
03943     else
03944         ret = FALSE;
03945     return ret;
03946 }
03947 
03948 struct hierarchy_data
03949 {
03950     PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo;
03951     HIMAGELIST imageList;
03952     DWORD selectedCert;
03953 };
03954 
03955 static LPARAM index_to_lparam(struct hierarchy_data *data, DWORD index)
03956 {
03957     CRYPT_PROVIDER_SGNR *provSigner = WTHelperGetProvSignerFromChain(
03958      (CRYPT_PROVIDER_DATA *)data->pCertViewInfo->u.pCryptProviderData,
03959      data->pCertViewInfo->idxSigner, data->pCertViewInfo->fCounterSigner,
03960      data->pCertViewInfo->idxCounterSigner);
03961 
03962     /* Takes advantage of the fact that a pointer is 32-bit aligned, and
03963      * therefore always even.
03964      */
03965     if (index == provSigner->csCertChain - 1)
03966         return (LPARAM)data;
03967     return index << 1 | 1;
03968 }
03969 
03970 static inline DWORD lparam_to_index(struct hierarchy_data *data, LPARAM lp)
03971 {
03972     CRYPT_PROVIDER_SGNR *provSigner = WTHelperGetProvSignerFromChain(
03973      (CRYPT_PROVIDER_DATA *)data->pCertViewInfo->u.pCryptProviderData,
03974      data->pCertViewInfo->idxSigner, data->pCertViewInfo->fCounterSigner,
03975      data->pCertViewInfo->idxCounterSigner);
03976 
03977     if (!(lp & 1))
03978         return provSigner->csCertChain - 1;
03979     return lp >> 1;
03980 }
03981 
03982 static struct hierarchy_data *get_hierarchy_data_from_tree_item(HWND tree,
03983  HTREEITEM hItem)
03984 {
03985     struct hierarchy_data *data = NULL;
03986     HTREEITEM root = NULL;
03987 
03988     do {
03989         HTREEITEM parent = (HTREEITEM)SendMessageW(tree, TVM_GETNEXTITEM,
03990          TVGN_PARENT, (LPARAM)hItem);
03991 
03992         if (!parent)
03993             root = hItem;
03994         hItem = parent;
03995     } while (hItem);
03996     if (root)
03997     {
03998         TVITEMW item;
03999 
04000         item.mask = TVIF_PARAM;
04001         item.hItem = root;
04002         SendMessageW(tree, TVM_GETITEMW, 0, (LPARAM)&item);
04003         data = (struct hierarchy_data *)item.lParam;
04004     }
04005     return data;
04006 }
04007 
04008 static WCHAR *get_cert_display_name(PCCERT_CONTEXT cert)
04009 {
04010     WCHAR *name = get_cert_property_as_string(cert, CERT_FRIENDLY_NAME_PROP_ID);
04011 
04012     if (!name)
04013         name = get_cert_name_string(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0);
04014     return name;
04015 }
04016 
04017 static void show_cert_chain(HWND hwnd, struct hierarchy_data *data)
04018 {
04019     HWND tree = GetDlgItem(hwnd, IDC_CERTPATH);
04020     CRYPT_PROVIDER_SGNR *provSigner = WTHelperGetProvSignerFromChain(
04021      (CRYPT_PROVIDER_DATA *)data->pCertViewInfo->u.pCryptProviderData,
04022      data->pCertViewInfo->idxSigner, data->pCertViewInfo->fCounterSigner,
04023      data->pCertViewInfo->idxCounterSigner);
04024     DWORD i;
04025     HTREEITEM parent = NULL;
04026 
04027     SendMessageW(tree, TVM_SETIMAGELIST, TVSIL_NORMAL, (LPARAM)data->imageList);
04028     for (i = provSigner->csCertChain; i; i--)
04029     {
04030         LPWSTR name;
04031 
04032         name = get_cert_display_name(provSigner->pasCertChain[i - 1].pCert);
04033         if (name)
04034         {
04035             TVINSERTSTRUCTW tvis;
04036 
04037             tvis.hParent = parent;
04038             tvis.hInsertAfter = TVI_LAST;
04039             tvis.u.item.mask = TVIF_TEXT | TVIF_STATE | TVIF_IMAGE |
04040              TVIF_SELECTEDIMAGE | TVIF_PARAM;
04041             tvis.u.item.pszText = name;
04042             tvis.u.item.state = TVIS_EXPANDED;
04043             tvis.u.item.stateMask = TVIS_EXPANDED;
04044             if (i == 1 && (!provSigner->pChainContext ||
04045              provSigner->pChainContext->TrustStatus.dwErrorStatus &
04046              CERT_TRUST_IS_PARTIAL_CHAIN))
04047             {
04048                 /* The root of the chain has a special case:  if the chain is
04049                  * a partial chain, the icon is a warning icon rather than an
04050                  * error icon.
04051                  */
04052                 tvis.u.item.iImage = 2;
04053             }
04054             else if (provSigner->pasCertChain[i - 1].pChainElement->TrustStatus.
04055              dwErrorStatus == 0)
04056                 tvis.u.item.iImage = 0;
04057             else
04058                 tvis.u.item.iImage = 1;
04059             tvis.u.item.iSelectedImage = tvis.u.item.iImage;
04060             tvis.u.item.lParam = index_to_lparam(data, i - 1);
04061             parent = (HTREEITEM)SendMessageW(tree, TVM_INSERTITEMW, 0,
04062              (LPARAM)&tvis);
04063             HeapFree(GetProcessHeap(), 0, name);
04064         }
04065     }
04066 }
04067 
04068 static void set_certificate_status(HWND hwnd, const CRYPT_PROVIDER_CERT *cert)
04069 {
04070     /* Select all the text in the control, the next update will replace it */
04071     SendMessageW(hwnd, EM_SETSEL, 0, -1);
04072     /* Set the highest priority error messages first. */
04073     if (!(cert->dwConfidence & CERT_CONFIDENCE_SIG))
04074         add_string_resource_to_control(hwnd, IDS_CERTIFICATE_BAD_SIGNATURE);
04075     else if (!(cert->dwConfidence & CERT_CONFIDENCE_TIME))
04076         add_string_resource_to_control(hwnd, IDS_CERTIFICATE_BAD_TIME);
04077     else if (!(cert->dwConfidence & CERT_CONFIDENCE_TIMENEST))
04078         add_string_resource_to_control(hwnd, IDS_CERTIFICATE_BAD_TIMENEST);
04079     else if (cert->dwRevokedReason)
04080         add_string_resource_to_control(hwnd, IDS_CERTIFICATE_REVOKED);
04081     else
04082         add_string_resource_to_control(hwnd, IDS_CERTIFICATE_VALID);
04083 }
04084 
04085 static void set_certificate_status_for_end_cert(HWND hwnd,
04086  PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo)
04087 {
04088     HWND status = GetDlgItem(hwnd, IDC_CERTIFICATESTATUSTEXT);
04089     CRYPT_PROVIDER_SGNR *provSigner = WTHelperGetProvSignerFromChain(
04090      (CRYPT_PROVIDER_DATA *)pCertViewInfo->u.pCryptProviderData,
04091      pCertViewInfo->idxSigner, pCertViewInfo->fCounterSigner,
04092      pCertViewInfo->idxCounterSigner);
04093     CRYPT_PROVIDER_CERT *provCert = WTHelperGetProvCertFromChain(provSigner,
04094      pCertViewInfo->idxCert);
04095 
04096     set_certificate_status(status, provCert);
04097 }
04098 
04099 static void show_cert_hierarchy(HWND hwnd, struct hierarchy_data *data)
04100 {
04101     /* Disable view certificate button until a certificate is selected */
04102     EnableWindow(GetDlgItem(hwnd, IDC_VIEWCERTIFICATE), FALSE);
04103     show_cert_chain(hwnd, data);
04104     set_certificate_status_for_end_cert(hwnd, data->pCertViewInfo);
04105 }
04106 
04107 static void show_dialog_for_selected_cert(HWND hwnd)
04108 {
04109     HWND tree = GetDlgItem(hwnd, IDC_CERTPATH);
04110     TVITEMW item;
04111     struct hierarchy_data *data;
04112     DWORD selection;
04113 
04114     memset(&item, 0, sizeof(item));
04115     item.mask = TVIF_HANDLE | TVIF_PARAM;
04116     item.hItem = (HTREEITEM)SendMessageW(tree, TVM_GETNEXTITEM, TVGN_CARET, 0);
04117     SendMessageW(tree, TVM_GETITEMW, 0, (LPARAM)&item);
04118     data = get_hierarchy_data_from_tree_item(tree, item.hItem);
04119     selection = lparam_to_index(data, item.lParam);
04120     if (selection != 0)
04121     {
04122         CRYPT_PROVIDER_SGNR *provSigner;
04123         CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo;
04124         BOOL changed = FALSE;
04125 
04126         provSigner = WTHelperGetProvSignerFromChain(
04127          (CRYPT_PROVIDER_DATA *)data->pCertViewInfo->u.pCryptProviderData,
04128          data->pCertViewInfo->idxSigner,
04129          data->pCertViewInfo->fCounterSigner,
04130          data->pCertViewInfo->idxCounterSigner);
04131         memset(&viewInfo, 0, sizeof(viewInfo));
04132         viewInfo.dwSize = sizeof(viewInfo);
04133         viewInfo.dwFlags = data->pCertViewInfo->dwFlags;
04134         viewInfo.szTitle = data->pCertViewInfo->szTitle;
04135         viewInfo.pCertContext = provSigner->pasCertChain[selection].pCert;
04136         viewInfo.cStores = data->pCertViewInfo->cStores;
04137         viewInfo.rghStores = data->pCertViewInfo->rghStores;
04138         viewInfo.cPropSheetPages = data->pCertViewInfo->cPropSheetPages;
04139         viewInfo.rgPropSheetPages = data->pCertViewInfo->rgPropSheetPages;
04140         viewInfo.nStartPage = data->pCertViewInfo->nStartPage;
04141         CryptUIDlgViewCertificateW(&viewInfo, &changed);
04142         if (changed)
04143         {
04144             /* Delete the contents of the tree */
04145             SendMessageW(tree, TVM_DELETEITEM, 0, (LPARAM)TVI_ROOT);
04146             /* Reinitialize the tree */
04147             show_cert_hierarchy(hwnd, data);
04148         }
04149     }
04150 }
04151 
04152 static LRESULT CALLBACK hierarchy_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
04153  LPARAM lp)
04154 {
04155     PROPSHEETPAGEW *page;
04156     struct hierarchy_data *data;
04157     LRESULT ret = 0;
04158     HWND tree = GetDlgItem(hwnd, IDC_CERTPATH);
04159 
04160     TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd, msg, wp, lp);
04161 
04162     switch (msg)
04163     {
04164     case WM_INITDIALOG:
04165         page = (PROPSHEETPAGEW *)lp;
04166         data = (struct hierarchy_data *)page->lParam;
04167         show_cert_hierarchy(hwnd, data);
04168         break;
04169     case WM_NOTIFY:
04170     {
04171         NMHDR *hdr;
04172 
04173         hdr = (NMHDR *)lp;
04174         switch (hdr->code)
04175         {
04176         case TVN_SELCHANGEDW:
04177         {
04178             NMTREEVIEWW *nm = (NMTREEVIEWW*)lp;
04179             DWORD selection;
04180             CRYPT_PROVIDER_SGNR *provSigner;
04181 
04182             data = get_hierarchy_data_from_tree_item(tree, nm->itemNew.hItem);
04183             selection = lparam_to_index(data, nm->itemNew.lParam);
04184             provSigner = WTHelperGetProvSignerFromChain(
04185              (CRYPT_PROVIDER_DATA *)data->pCertViewInfo->u.pCryptProviderData,
04186              data->pCertViewInfo->idxSigner,
04187              data->pCertViewInfo->fCounterSigner,
04188              data->pCertViewInfo->idxCounterSigner);
04189             EnableWindow(GetDlgItem(hwnd, IDC_VIEWCERTIFICATE), selection != 0);
04190             set_certificate_status(GetDlgItem(hwnd, IDC_CERTIFICATESTATUSTEXT),
04191              &provSigner->pasCertChain[selection]);
04192             break;
04193         }
04194         case NM_DBLCLK:
04195             show_dialog_for_selected_cert(hwnd);
04196             SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, 1);
04197             ret = 1;
04198             break;
04199         }
04200         break;
04201     }
04202     case WM_COMMAND:
04203         switch (wp)
04204         {
04205         case IDC_VIEWCERTIFICATE:
04206             show_dialog_for_selected_cert(hwnd);
04207             break;
04208         }
04209         break;
04210     case WM_REFRESH_VIEW:
04211     {
04212         TVITEMW item;
04213 
04214         /* Get hierarchy data */
04215         memset(&item, 0, sizeof(item));
04216         item.mask = TVIF_HANDLE | TVIF_PARAM;
04217         item.hItem = (HTREEITEM)SendMessageW(tree, TVM_GETNEXTITEM, TVGN_ROOT,
04218          0);
04219         data = get_hierarchy_data_from_tree_item(tree, item.hItem);
04220         /* Delete the contents of the tree */
04221         SendMessageW(tree, TVM_DELETEITEM, 0, (LPARAM)TVI_ROOT);
04222         /* Reinitialize the tree */
04223         show_cert_hierarchy(hwnd, data);
04224         break;
04225     }
04226     }
04227     return ret;
04228 }
04229 
04230 static UINT CALLBACK hierarchy_callback(HWND hwnd, UINT msg,
04231  PROPSHEETPAGEW *page)
04232 {
04233     struct hierarchy_data *data;
04234 
04235     switch (msg)
04236     {
04237     case PSPCB_RELEASE:
04238         data = (struct hierarchy_data *)page->lParam;
04239         ImageList_Destroy(data->imageList);
04240         HeapFree(GetProcessHeap(), 0, data);
04241         break;
04242     }
04243     return 0;
04244 }
04245 
04246 static BOOL init_hierarchy_page(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo,
04247  PROPSHEETPAGEW *page)
04248 {
04249     struct hierarchy_data *data = HeapAlloc(GetProcessHeap(), 0,
04250      sizeof(struct hierarchy_data));
04251     BOOL ret = FALSE;
04252 
04253     if (data)
04254     {
04255         data->imageList = ImageList_Create(16, 16, ILC_COLOR4 | ILC_MASK, 2, 0);
04256         if (data->imageList)
04257         {
04258             HBITMAP bmp;
04259             COLORREF backColor = RGB(255, 0, 255);
04260 
04261             data->pCertViewInfo = pCertViewInfo;
04262             data->selectedCert = 0xffffffff;
04263 
04264             bmp = LoadBitmapW(hInstance, MAKEINTRESOURCEW(IDB_SMALL_ICONS));
04265             ImageList_AddMasked(data->imageList, bmp, backColor);
04266             DeleteObject(bmp);
04267             ImageList_SetBkColor(data->imageList, CLR_NONE);
04268 
04269             memset(page, 0, sizeof(PROPSHEETPAGEW));
04270             page->dwSize = sizeof(PROPSHEETPAGEW);
04271             page->dwFlags = PSP_USECALLBACK;
04272             page->hInstance = hInstance;
04273             page->u.pszTemplate = MAKEINTRESOURCEW(IDD_HIERARCHY);
04274             page->pfnDlgProc = hierarchy_dlg_proc;
04275             page->lParam = (LPARAM)data;
04276             page->pfnCallback = hierarchy_callback;
04277             ret = TRUE;
04278         }
04279         else
04280             HeapFree(GetProcessHeap(), 0, data);
04281     }
04282     return ret;
04283 }
04284 
04285 static int CALLBACK cert_prop_sheet_proc(HWND hwnd, UINT msg, LPARAM lp)
04286 {
04287     RECT rc;
04288 
04289     TRACE("(%p, %08x, %08lx)\n", hwnd, msg, lp);
04290 
04291     switch (msg)
04292     {
04293     case PSCB_INITIALIZED:
04294         /* Get cancel button's position.. */
04295         GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rc);
04296         MapWindowPoints( 0, hwnd, (POINT *)&rc, 2 );
04297         /* hide the cancel button.. */
04298         ShowWindow(GetDlgItem(hwnd, IDCANCEL), FALSE);
04299         /* and move the OK button to the cancel button's original position. */
04300         SetWindowPos(GetDlgItem(hwnd, IDOK), 0, rc.left, rc.top, 0, 0,
04301                      SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW );
04302         break;
04303     }
04304     return 0;
04305 }
04306 
04307 static BOOL show_cert_dialog(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo,
04308  CRYPT_PROVIDER_CERT *provCert, BOOL *pfPropertiesChanged)
04309 {
04310     static const WCHAR riched[] = { 'r','i','c','h','e','d','2','0',0 };
04311     DWORD nPages;
04312     PROPSHEETPAGEW *pages;
04313     BOOL ret = FALSE;
04314     HMODULE lib = LoadLibraryW(riched);
04315 
04316     nPages = pCertViewInfo->cPropSheetPages + 1; /* one for the General tab */
04317     if (!(pCertViewInfo->dwFlags & CRYPTUI_HIDE_DETAILPAGE))
04318         nPages++;
04319     if (!(pCertViewInfo->dwFlags & CRYPTUI_HIDE_HIERARCHYPAGE))
04320         nPages++;
04321     pages = HeapAlloc(GetProcessHeap(), 0, nPages * sizeof(PROPSHEETPAGEW));
04322     if (pages)
04323     {
04324         PROPSHEETHEADERW hdr;
04325         CRYPTUI_INITDIALOG_STRUCT *init = NULL;
04326         DWORD i;
04327 
04328         memset(&hdr, 0, sizeof(hdr));
04329         hdr.dwSize = sizeof(hdr);
04330         hdr.dwFlags = PSH_NOAPPLYNOW | PSH_PROPSHEETPAGE | PSH_USECALLBACK;
04331         hdr.hInstance = hInstance;
04332         if (pCertViewInfo->szTitle)
04333             hdr.pszCaption = pCertViewInfo->szTitle;
04334         else
04335             hdr.pszCaption = MAKEINTRESOURCEW(IDS_CERTIFICATE);
04336         init_general_page(pCertViewInfo, &pages[hdr.nPages++]);
04337         if (!(pCertViewInfo->dwFlags & CRYPTUI_HIDE_DETAILPAGE))
04338         {
04339             if (init_detail_page(pCertViewInfo, pfPropertiesChanged,
04340              &pages[hdr.nPages]))
04341                 hdr.nPages++;
04342         }
04343         if (!(pCertViewInfo->dwFlags & CRYPTUI_HIDE_HIERARCHYPAGE))
04344         {
04345             if (init_hierarchy_page(pCertViewInfo, &pages[hdr.nPages]))
04346                 hdr.nPages++;
04347         }
04348         /* Copy each additional page, and create the init dialog struct for it
04349          */
04350         if (pCertViewInfo->cPropSheetPages)
04351         {
04352             init = HeapAlloc(GetProcessHeap(), 0,
04353              pCertViewInfo->cPropSheetPages *
04354              sizeof(CRYPTUI_INITDIALOG_STRUCT));
04355             if (init)
04356             {
04357                 for (i = 0; i < pCertViewInfo->cPropSheetPages; i++)
04358                 {
04359                     memcpy(&pages[hdr.nPages + i],
04360                      &pCertViewInfo->rgPropSheetPages[i],
04361                      sizeof(PROPSHEETPAGEW));
04362                     init[i].lParam = pCertViewInfo->rgPropSheetPages[i].lParam;
04363                     init[i].pCertContext = pCertViewInfo->pCertContext;
04364                     pages[hdr.nPages + i].lParam = (LPARAM)&init[i];
04365                 }
04366                 if (pCertViewInfo->nStartPage & 0x8000)
04367                 {
04368                     /* Start page index is relative to the number of default
04369                      * pages
04370                      */
04371                     hdr.u2.nStartPage = pCertViewInfo->nStartPage + hdr.nPages;
04372                 }
04373                 else
04374                     hdr.u2.nStartPage = pCertViewInfo->nStartPage;
04375                 hdr.nPages = nPages;
04376                 ret = TRUE;
04377             }
04378             else
04379                 SetLastError(ERROR_OUTOFMEMORY);
04380         }
04381         else
04382         {
04383             /* Ignore the relative flag if there aren't any additional pages */
04384             hdr.u2.nStartPage = pCertViewInfo->nStartPage & 0x7fff;
04385             ret = TRUE;
04386         }
04387         if (ret)
04388         {
04389             INT_PTR l;
04390 
04391             hdr.u3.ppsp = pages;
04392             hdr.pfnCallback = cert_prop_sheet_proc;
04393             l = PropertySheetW(&hdr);
04394             if (l == 0)
04395             {
04396                 SetLastError(ERROR_CANCELLED);
04397                 ret = FALSE;
04398             }
04399         }
04400         HeapFree(GetProcessHeap(), 0, init);
04401         HeapFree(GetProcessHeap(), 0, pages);
04402     }
04403     else
04404         SetLastError(ERROR_OUTOFMEMORY);
04405     FreeLibrary(lib);
04406     return ret;
04407 }
04408 
04409 /***********************************************************************
04410  *      CryptUIDlgViewCertificateW (CRYPTUI.@)
04411  */
04412 BOOL WINAPI CryptUIDlgViewCertificateW(
04413  PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo, BOOL *pfPropertiesChanged)
04414 {
04415     static GUID generic_cert_verify = WINTRUST_ACTION_GENERIC_CERT_VERIFY;
04416     CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo;
04417     WINTRUST_DATA wvt;
04418     WINTRUST_CERT_INFO cert;
04419     BOOL ret = FALSE;
04420     CRYPT_PROVIDER_SGNR *signer;
04421     CRYPT_PROVIDER_CERT *provCert = NULL;
04422 
04423     TRACE("(%p, %p)\n", pCertViewInfo, pfPropertiesChanged);
04424 
04425     if (pCertViewInfo->dwSize != sizeof(CRYPTUI_VIEWCERTIFICATE_STRUCTW))
04426     {
04427         SetLastError(ERROR_INVALID_PARAMETER);
04428         return FALSE;
04429     }
04430     /* Make a local copy in case we have to call WinVerifyTrust ourselves */
04431     memcpy(&viewInfo, pCertViewInfo, sizeof(viewInfo));
04432     if (!pCertViewInfo->u.hWVTStateData)
04433     {
04434         memset(&wvt, 0, sizeof(wvt));
04435         wvt.cbStruct = sizeof(wvt);
04436         wvt.dwUIChoice = WTD_UI_NONE;
04437         if (viewInfo.dwFlags &
04438          CRYPTUI_ENABLE_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT)
04439             wvt.fdwRevocationChecks |= WTD_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT;
04440         if (viewInfo.dwFlags & CRYPTUI_ENABLE_REVOCATION_CHECK_END_CERT)
04441             wvt.fdwRevocationChecks |= WTD_REVOCATION_CHECK_END_CERT;
04442         if (viewInfo.dwFlags & CRYPTUI_ENABLE_REVOCATION_CHECK_CHAIN)
04443             wvt.fdwRevocationChecks |= WTD_REVOCATION_CHECK_CHAIN;
04444         wvt.dwUnionChoice = WTD_CHOICE_CERT;
04445         memset(&cert, 0, sizeof(cert));
04446         cert.cbStruct = sizeof(cert);
04447         cert.psCertContext = (CERT_CONTEXT *)viewInfo.pCertContext;
04448         cert.chStores = viewInfo.cStores;
04449         cert.pahStores = viewInfo.rghStores;
04450         wvt.u.pCert = &cert;
04451         wvt.dwStateAction = WTD_STATEACTION_VERIFY;
04452         WinVerifyTrust(NULL, &generic_cert_verify, &wvt);
04453         viewInfo.u.pCryptProviderData =
04454          WTHelperProvDataFromStateData(wvt.hWVTStateData);
04455         signer = WTHelperGetProvSignerFromChain(
04456          (CRYPT_PROVIDER_DATA *)viewInfo.u.pCryptProviderData, 0, FALSE, 0);
04457         provCert = WTHelperGetProvCertFromChain(signer, 0);
04458         ret = TRUE;
04459     }
04460     else
04461     {
04462         viewInfo.u.pCryptProviderData =
04463          WTHelperProvDataFromStateData(viewInfo.u.hWVTStateData);
04464         signer = WTHelperGetProvSignerFromChain(
04465          (CRYPT_PROVIDER_DATA *)viewInfo.u.pCryptProviderData,
04466          viewInfo.idxSigner, viewInfo.fCounterSigner,
04467          viewInfo.idxCounterSigner);
04468         provCert = WTHelperGetProvCertFromChain(signer, viewInfo.idxCert);
04469         ret = TRUE;
04470     }
04471     if (ret)
04472     {
04473         ret = show_cert_dialog(&viewInfo, provCert, pfPropertiesChanged);
04474         if (!pCertViewInfo->u.hWVTStateData)
04475         {
04476             wvt.dwStateAction = WTD_STATEACTION_CLOSE;
04477             WinVerifyTrust(NULL, &generic_cert_verify, &wvt);
04478         }
04479     }
04480     return ret;
04481 }
04482 
04483 /***********************************************************************
04484  *      CryptUIDlgViewContext (CRYPTUI.@)
04485  */
04486 BOOL WINAPI CryptUIDlgViewContext(DWORD dwContextType, LPVOID pvContext,
04487  HWND hwnd, LPCWSTR pwszTitle, DWORD dwFlags, LPVOID pvReserved)
04488 {
04489     BOOL ret;
04490 
04491     TRACE("(%d, %p, %p, %s, %08x, %p)\n", dwContextType, pvContext, hwnd,
04492      debugstr_w(pwszTitle), dwFlags, pvReserved);
04493 
04494     switch (dwContextType)
04495     {
04496     case CERT_STORE_CERTIFICATE_CONTEXT:
04497     {
04498         CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo;
04499 
04500         memset(&viewInfo, 0, sizeof(viewInfo));
04501         viewInfo.dwSize = sizeof(viewInfo);
04502         viewInfo.hwndParent = hwnd;
04503         viewInfo.szTitle = pwszTitle;
04504         viewInfo.pCertContext = pvContext;
04505         ret = CryptUIDlgViewCertificateW(&viewInfo, NULL);
04506         break;
04507     }
04508     default:
04509         FIXME("unimplemented for context type %d\n", dwContextType);
04510         SetLastError(E_INVALIDARG);
04511         ret = FALSE;
04512     }
04513     return ret;
04514 }
04515 
04516 /* Decodes a cert's basic constraints extension (either szOID_BASIC_CONSTRAINTS
04517  * or szOID_BASIC_CONSTRAINTS2, whichever is present) to determine if it
04518  * should be a CA.  If neither extension is present, returns
04519  * defaultIfNotSpecified.
04520  */
04521 static BOOL is_ca_cert(PCCERT_CONTEXT cert, BOOL defaultIfNotSpecified)
04522 {
04523     BOOL isCA = defaultIfNotSpecified;
04524     PCERT_EXTENSION ext = CertFindExtension(szOID_BASIC_CONSTRAINTS,
04525      cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension);
04526 
04527     if (ext)
04528     {
04529         CERT_BASIC_CONSTRAINTS_INFO *info;
04530         DWORD size = 0;
04531 
04532         if (CryptDecodeObjectEx(X509_ASN_ENCODING, szOID_BASIC_CONSTRAINTS,
04533          ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_ALLOC_FLAG,
04534          NULL, &info, &size))
04535         {
04536             if (info->SubjectType.cbData == 1)
04537                 isCA = info->SubjectType.pbData[0] & CERT_CA_SUBJECT_FLAG;
04538             LocalFree(info);
04539         }
04540     }
04541     else
04542     {
04543         ext = CertFindExtension(szOID_BASIC_CONSTRAINTS2,
04544          cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension);
04545         if (ext)
04546         {
04547             CERT_BASIC_CONSTRAINTS2_INFO info;
04548             DWORD size = sizeof(CERT_BASIC_CONSTRAINTS2_INFO);
04549 
04550             if (CryptDecodeObjectEx(X509_ASN_ENCODING,
04551              szOID_BASIC_CONSTRAINTS2, ext->Value.pbData, ext->Value.cbData,
04552              0, NULL, &info, &size))
04553                 isCA = info.fCA;
04554         }
04555     }
04556     return isCA;
04557 }
04558 
04559 static HCERTSTORE choose_store_for_cert(PCCERT_CONTEXT cert)
04560 {
04561     LPCWSTR storeName;
04562 
04563     if (is_ca_cert(cert, TRUE))
04564         storeName = ca;
04565     else
04566         storeName = addressBook;
04567     return CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, 0,
04568      CERT_SYSTEM_STORE_CURRENT_USER, storeName);
04569 }
04570 
04571 static BOOL import_cert(PCCERT_CONTEXT cert, HCERTSTORE hDestCertStore)
04572 {
04573     HCERTSTORE store;
04574     BOOL ret;
04575 
04576     if (!cert)
04577     {
04578         SetLastError(E_INVALIDARG);
04579         return FALSE;
04580     }
04581     if (hDestCertStore) store = hDestCertStore;
04582     else
04583     {
04584         if (!(store = choose_store_for_cert(cert)))
04585         {
04586             WARN("unable to open certificate store\n");
04587             return FALSE;
04588         }
04589     }
04590     ret = CertAddCertificateContextToStore(store, cert,
04591      CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES, NULL);
04592     if (!hDestCertStore) CertCloseStore(store, 0);
04593     return ret;
04594 }
04595 
04596 static BOOL import_crl(PCCRL_CONTEXT crl, HCERTSTORE hDestCertStore)
04597 {
04598     HCERTSTORE store;
04599     BOOL ret;
04600 
04601     if (!crl)
04602     {
04603         SetLastError(E_INVALIDARG);
04604         return FALSE;
04605     }
04606     if (hDestCertStore) store = hDestCertStore;
04607     else
04608     {
04609         if (!(store = CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, 0,
04610          CERT_SYSTEM_STORE_CURRENT_USER, ca)))
04611         {
04612             WARN("unable to open certificate store\n");
04613             return FALSE;
04614         }
04615     }
04616     ret = CertAddCRLContextToStore(store, crl,
04617      CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES, NULL);
04618     if (!hDestCertStore) CertCloseStore(store, 0);
04619     return ret;
04620 }
04621 
04622 static BOOL import_ctl(PCCTL_CONTEXT ctl, HCERTSTORE hDestCertStore)
04623 {
04624     HCERTSTORE store;
04625     BOOL ret;
04626 
04627     if (!ctl)
04628     {
04629         SetLastError(E_INVALIDARG);
04630         return FALSE;
04631     }
04632     if (hDestCertStore) store = hDestCertStore;
04633     else
04634     {
04635         static const WCHAR trust[] = { 'T','r','u','s','t',0 };
04636 
04637         if (!(store = CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, 0,
04638          CERT_SYSTEM_STORE_CURRENT_USER, trust)))
04639         {
04640             WARN("unable to open certificate store\n");
04641             return FALSE;
04642         }
04643     }
04644     ret = CertAddCTLContextToStore(store, ctl,
04645      CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES, NULL);
04646     if (!hDestCertStore) CertCloseStore(store, 0);
04647     return ret;
04648 }
04649 
04650 /* Checks type, a type such as CERT_QUERY_CONTENT_CERT returned by
04651  * CryptQueryObject, against the allowed types.  Returns TRUE if the
04652  * type is allowed, FALSE otherwise.
04653  */
04654 static BOOL check_context_type(DWORD dwFlags, DWORD type)
04655 {
04656     BOOL ret;
04657 
04658     if (dwFlags &
04659      (CRYPTUI_WIZ_IMPORT_ALLOW_CERT | CRYPTUI_WIZ_IMPORT_ALLOW_CRL |
04660      CRYPTUI_WIZ_IMPORT_ALLOW_CTL))
04661     {
04662         switch (type)
04663         {
04664         case CERT_QUERY_CONTENT_CERT:
04665         case CERT_QUERY_CONTENT_SERIALIZED_CERT:
04666             ret = dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CERT;
04667             break;
04668         case CERT_QUERY_CONTENT_CRL:
04669         case CERT_QUERY_CONTENT_SERIALIZED_CRL:
04670             ret = dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CRL;
04671             break;
04672         case CERT_QUERY_CONTENT_CTL:
04673         case CERT_QUERY_CONTENT_SERIALIZED_CTL:
04674             ret = dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CTL;
04675             break;
04676         default:
04677             /* The remaining types contain more than one type, so allow
04678              * any combination.
04679              */
04680             ret = TRUE;
04681         }
04682     }
04683     else
04684     {
04685         /* No allowed types specified, so any type is allowed */
04686         ret = TRUE;
04687     }
04688     if (!ret)
04689         SetLastError(E_INVALIDARG);
04690     return ret;
04691 }
04692 
04693 
04694 static void import_warning(DWORD dwFlags, HWND hwnd, LPCWSTR szTitle,
04695  int warningID)
04696 {
04697     if (!(dwFlags & CRYPTUI_WIZ_NO_UI))
04698     {
04699         WCHAR title[MAX_STRING_LEN], error[MAX_STRING_LEN];
04700         LPCWSTR pTitle;
04701 
04702         if (szTitle)
04703             pTitle = szTitle;
04704         else
04705         {
04706             LoadStringW(hInstance, IDS_IMPORT_WIZARD, title,
04707              sizeof(title) / sizeof(title[0]));
04708             pTitle = title;
04709         }
04710         LoadStringW(hInstance, warningID, error,
04711          sizeof(error) / sizeof(error[0]));
04712         MessageBoxW(hwnd, error, pTitle, MB_ICONERROR | MB_OK);
04713     }
04714 }
04715 
04716 static void import_warn_type_mismatch(DWORD dwFlags, HWND hwnd, LPCWSTR szTitle)
04717 {
04718     import_warning(dwFlags, hwnd, szTitle, IDS_IMPORT_TYPE_MISMATCH);
04719 }
04720 
04721 static BOOL check_store_context_type(DWORD dwFlags, HCERTSTORE store)
04722 {
04723     BOOL ret;
04724 
04725     if (dwFlags &
04726      (CRYPTUI_WIZ_IMPORT_ALLOW_CERT | CRYPTUI_WIZ_IMPORT_ALLOW_CRL |
04727      CRYPTUI_WIZ_IMPORT_ALLOW_CTL))
04728     {
04729         PCCERT_CONTEXT cert;
04730         PCCRL_CONTEXT crl;
04731         PCCTL_CONTEXT ctl;
04732 
04733         ret = TRUE;
04734         if ((cert = CertEnumCertificatesInStore(store, NULL)))
04735         {
04736             CertFreeCertificateContext(cert);
04737             if (!(dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CERT))
04738                 ret = FALSE;
04739         }
04740         if (ret && (crl = CertEnumCRLsInStore(store, NULL)))
04741         {
04742             CertFreeCRLContext(crl);
04743             if (!(dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CRL))
04744                 ret = FALSE;
04745         }
04746         if (ret && (ctl = CertEnumCTLsInStore(store, NULL)))
04747         {
04748             CertFreeCTLContext(ctl);
04749             if (!(dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CTL))
04750                 ret = FALSE;
04751         }
04752     }
04753     else
04754         ret = TRUE;
04755     if (!ret)
04756         SetLastError(E_INVALIDARG);
04757     return ret;
04758 }
04759 
04760 static BOOL import_store(DWORD dwFlags, HWND hwnd, LPCWSTR szTitle,
04761  HCERTSTORE source, HCERTSTORE dest)
04762 {
04763     BOOL ret;
04764 
04765     if ((ret = check_store_context_type(dwFlags, source)))
04766     {
04767         PCCERT_CONTEXT cert = NULL;
04768         PCCRL_CONTEXT crl = NULL;
04769         PCCTL_CONTEXT ctl = NULL;
04770 
04771         do {
04772             cert = CertEnumCertificatesInStore(source, cert);
04773             if (cert)
04774                 ret = import_cert(cert, dest);
04775         } while (ret && cert);
04776         do {
04777             crl = CertEnumCRLsInStore(source, crl);
04778             if (crl)
04779                 ret = import_crl(crl, dest);
04780         } while (ret && crl);
04781         do {
04782             ctl = CertEnumCTLsInStore(source, ctl);
04783             if (ctl)
04784                 ret = import_ctl(ctl, dest);
04785         } while (ret && ctl);
04786     }
04787     else
04788         import_warn_type_mismatch(dwFlags, hwnd, szTitle);
04789     return ret;
04790 }
04791 
04792 static HCERTSTORE open_store_from_file(DWORD dwFlags, LPCWSTR fileName,
04793  DWORD *pContentType)
04794 {
04795     HCERTSTORE store = NULL;
04796     DWORD contentType = 0, expectedContentTypeFlags;
04797 
04798     if (dwFlags &
04799      (CRYPTUI_WIZ_IMPORT_ALLOW_CERT | CRYPTUI_WIZ_IMPORT_ALLOW_CRL |
04800      CRYPTUI_WIZ_IMPORT_ALLOW_CTL))
04801     {
04802         expectedContentTypeFlags =
04803          CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE |
04804          CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED |
04805          CERT_QUERY_CONTENT_FLAG_PFX;
04806         if (dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CERT)
04807             expectedContentTypeFlags |=
04808              CERT_QUERY_CONTENT_FLAG_CERT |
04809              CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT;
04810         if (dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CRL)
04811             expectedContentTypeFlags |=
04812              CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL |
04813              CERT_QUERY_CONTENT_FLAG_CRL;
04814         if (dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CTL)
04815             expectedContentTypeFlags |=
04816              CERT_QUERY_CONTENT_FLAG_CTL |
04817              CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL;
04818     }
04819     else
04820         expectedContentTypeFlags =
04821          CERT_QUERY_CONTENT_FLAG_CERT |
04822          CERT_QUERY_CONTENT_FLAG_CTL |
04823          CERT_QUERY_CONTENT_FLAG_CRL |
04824          CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE |
04825          CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT |
04826          CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL |
04827          CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL |
04828          CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED |
04829          CERT_QUERY_CONTENT_FLAG_PFX;
04830 
04831     CryptQueryObject(CERT_QUERY_OBJECT_FILE, fileName,
04832      expectedContentTypeFlags, CERT_QUERY_FORMAT_FLAG_ALL, 0, NULL,
04833      &contentType, NULL, &store, NULL, NULL);
04834     if (pContentType)
04835         *pContentType = contentType;
04836     return store;
04837 }
04838 
04839 static BOOL import_file(DWORD dwFlags, HWND hwnd, LPCWSTR szTitle,
04840  LPCWSTR fileName, HCERTSTORE dest)
04841 {
04842     HCERTSTORE source;
04843     BOOL ret;
04844 
04845     if ((source = open_store_from_file(dwFlags, fileName, NULL)))
04846     {
04847         ret = import_store(dwFlags, hwnd, szTitle, source, dest);
04848         CertCloseStore(source, 0);
04849     }
04850     else
04851         ret = FALSE;
04852     return ret;
04853 }
04854 
04855 struct ImportWizData
04856 {
04857     HFONT titleFont;
04858     DWORD dwFlags;
04859     LPCWSTR pwszWizardTitle;
04860     CRYPTUI_WIZ_IMPORT_SRC_INFO importSrc;
04861     LPWSTR fileName;
04862     DWORD contentType;
04863     BOOL freeSource;
04864     HCERTSTORE hDestCertStore;
04865     BOOL freeDest;
04866     BOOL autoDest;
04867     BOOL success;
04868 };
04869 
04870 static LRESULT CALLBACK import_welcome_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
04871  LPARAM lp)
04872 {
04873     LRESULT ret = 0;
04874 
04875     switch (msg)
04876     {
04877     case WM_INITDIALOG:
04878     {
04879         struct ImportWizData *data;
04880         PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp;
04881         WCHAR fontFace[MAX_STRING_LEN];
04882         HDC hDC = GetDC(hwnd);
04883         int height;
04884 
04885         data = (struct ImportWizData *)page->lParam;
04886         LoadStringW(hInstance, IDS_WIZARD_TITLE_FONT, fontFace,
04887          sizeof(fontFace) / sizeof(fontFace[0]));
04888         height = -MulDiv(12, GetDeviceCaps(hDC, LOGPIXELSY), 72);
04889         data->titleFont = CreateFontW(height, 0, 0, 0, FW_BOLD, 0, 0, 0,
04890          DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
04891          DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, fontFace);
04892         SendMessageW(GetDlgItem(hwnd, IDC_IMPORT_TITLE), WM_SETFONT,
04893          (WPARAM)data->titleFont, TRUE);
04894         ReleaseDC(hwnd, hDC);
04895         break;
04896     }
04897     case WM_NOTIFY:
04898     {
04899         NMHDR *hdr = (NMHDR *)lp;
04900 
04901         switch (hdr->code)
04902         {
04903         case PSN_SETACTIVE:
04904             PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0, PSWIZB_NEXT);
04905             ret = TRUE;
04906             break;
04907         }
04908         break;
04909     }
04910     }
04911     return ret;
04912 }
04913 
04914 static const WCHAR filter_cert[] = { '*','.','c','e','r',';','*','.',
04915  'c','r','t',0 };
04916 static const WCHAR filter_pfx[] = { '*','.','p','f','x',';','*','.',
04917  'p','1','2',0 };
04918 static const WCHAR filter_crl[] = { '*','.','c','r','l',0 };
04919 static const WCHAR filter_ctl[] = { '*','.','s','t','l',0 };
04920 static const WCHAR filter_serialized_store[] = { '*','.','s','s','t',0 };
04921 static const WCHAR filter_cms[] = { '*','.','s','p','c',';','*','.',
04922  'p','7','b',0 };
04923 static const WCHAR filter_all[] = { '*','.','*',0 };
04924 
04925 static struct StringToFilter
04926 {
04927     int     id;
04928     DWORD   allowFlags;
04929     LPCWSTR filter;
04930 } import_filters[] = {
04931  { IDS_IMPORT_FILTER_CERT, CRYPTUI_WIZ_IMPORT_ALLOW_CERT, filter_cert },
04932  { IDS_IMPORT_FILTER_PFX, 0, filter_pfx },
04933  { IDS_IMPORT_FILTER_CRL, CRYPTUI_WIZ_IMPORT_ALLOW_CRL, filter_crl },
04934  { IDS_IMPORT_FILTER_CTL, CRYPTUI_WIZ_IMPORT_ALLOW_CTL, filter_ctl },
04935  { IDS_IMPORT_FILTER_SERIALIZED_STORE, 0, filter_serialized_store },
04936  { IDS_IMPORT_FILTER_CMS, 0, filter_cms },
04937  { IDS_IMPORT_FILTER_ALL, 0, filter_all },
04938 };
04939 
04940 static WCHAR *make_import_file_filter(DWORD dwFlags)
04941 {
04942     DWORD i;
04943     int len, totalLen = 2;
04944     LPWSTR filter = NULL, str;
04945 
04946     for (i = 0; i < sizeof(import_filters) / sizeof(import_filters[0]); i++)
04947     {
04948         if (!import_filters[i].allowFlags || !dwFlags ||
04949          (dwFlags & import_filters[i].allowFlags))
04950         {
04951             len = LoadStringW(hInstance, import_filters[i].id, (LPWSTR)&str, 0);
04952             totalLen += len + strlenW(import_filters[i].filter) + 2;
04953         }
04954     }
04955     filter = HeapAlloc(GetProcessHeap(), 0, totalLen * sizeof(WCHAR));
04956     if (filter)
04957     {
04958         LPWSTR ptr;
04959 
04960         ptr = filter;
04961         for (i = 0; i < sizeof(import_filters) / sizeof(import_filters[0]); i++)
04962         {
04963             if (!import_filters[i].allowFlags || !dwFlags ||
04964              (dwFlags & import_filters[i].allowFlags))
04965             {
04966                 len = LoadStringW(hInstance, import_filters[i].id,
04967                  (LPWSTR)&str, 0);
04968                 memcpy(ptr, str, len * sizeof(WCHAR));
04969                 ptr += len;
04970                 *ptr++ = 0;
04971                 strcpyW(ptr, import_filters[i].filter);
04972                 ptr += strlenW(import_filters[i].filter) + 1;
04973             }
04974         }
04975         *ptr++ = 0;
04976     }
04977     return filter;
04978 }
04979 
04980 static BOOL import_validate_filename(HWND hwnd, struct ImportWizData *data,
04981  LPCWSTR fileName)
04982 {
04983     HANDLE file;
04984     BOOL ret = FALSE;
04985 
04986     file = CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ, NULL,
04987      OPEN_EXISTING, 0, NULL);
04988     if (file != INVALID_HANDLE_VALUE)
04989     {
04990         HCERTSTORE source = open_store_from_file(data->dwFlags, fileName,
04991          &data->contentType);
04992         int warningID = 0;
04993 
04994         if (!source)
04995             warningID = IDS_IMPORT_BAD_FORMAT;
04996         else if (!check_store_context_type(data->dwFlags, source))
04997             warningID = IDS_IMPORT_TYPE_MISMATCH;
04998         else
04999         {
05000             data->importSrc.dwSubjectChoice =
05001              CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_STORE;
05002             data->importSrc.u.hCertStore = source;
05003             data->freeSource = TRUE;
05004             ret = TRUE;
05005         }
05006         if (warningID)
05007         {
05008             import_warning(data->dwFlags, hwnd, data->pwszWizardTitle,
05009              warningID);
05010         }
05011         CloseHandle(file);
05012     }
05013     else
05014     {
05015         WCHAR title[MAX_STRING_LEN], error[MAX_STRING_LEN];
05016         LPCWSTR pTitle;
05017         LPWSTR msgBuf, fullError;
05018 
05019         if (data->pwszWizardTitle)
05020             pTitle = data->pwszWizardTitle;
05021         else
05022         {
05023             LoadStringW(hInstance, IDS_IMPORT_WIZARD, title,
05024              sizeof(title) / sizeof(title[0]));
05025             pTitle = title;
05026         }
05027         LoadStringW(hInstance, IDS_IMPORT_OPEN_FAILED, error,
05028          sizeof(error) / sizeof(error[0]));
05029         FormatMessageW(
05030          FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL,
05031          GetLastError(), 0, (LPWSTR) &msgBuf, 0, NULL);
05032         fullError = HeapAlloc(GetProcessHeap(), 0,
05033          (strlenW(error) + strlenW(fileName) + strlenW(msgBuf) + 3)
05034          * sizeof(WCHAR));
05035         if (fullError)
05036         {
05037             LPWSTR ptr = fullError;
05038 
05039             strcpyW(ptr, error);
05040             ptr += strlenW(error);
05041             strcpyW(ptr, fileName);
05042             ptr += strlenW(fileName);
05043             *ptr++ = ':';
05044             *ptr++ = '\n';
05045             strcpyW(ptr, msgBuf);
05046             MessageBoxW(hwnd, fullError, pTitle, MB_ICONERROR | MB_OK);
05047             HeapFree(GetProcessHeap(), 0, fullError);
05048         }
05049         LocalFree(msgBuf);
05050     }
05051     return ret;
05052 }
05053 
05054 static LRESULT CALLBACK import_file_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
05055  LPARAM lp)
05056 {
05057     LRESULT ret = 0;
05058     struct ImportWizData *data;
05059 
05060     switch (msg)
05061     {
05062     case WM_INITDIALOG:
05063     {
05064         PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp;
05065 
05066         data = (struct ImportWizData *)page->lParam;
05067         SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
05068         if (data->fileName)
05069         {
05070             HWND fileNameEdit = GetDlgItem(hwnd, IDC_IMPORT_FILENAME);
05071 
05072             SendMessageW(fileNameEdit, WM_SETTEXT, 0, (LPARAM)data->fileName);
05073         }
05074         break;
05075     }
05076     case WM_NOTIFY:
05077     {
05078         NMHDR *hdr = (NMHDR *)lp;
05079 
05080         switch (hdr->code)
05081         {
05082         case PSN_SETACTIVE:
05083             PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0,
05084              PSWIZB_BACK | PSWIZB_NEXT);
05085             ret = TRUE;
05086             break;
05087         case PSN_WIZNEXT:
05088         {
05089             HWND fileNameEdit = GetDlgItem(hwnd, IDC_IMPORT_FILENAME);
05090             DWORD len = SendMessageW(fileNameEdit, WM_GETTEXTLENGTH, 0, 0);
05091 
05092             data = (struct ImportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
05093             if (!len)
05094             {
05095                 import_warning(data->dwFlags, hwnd, data->pwszWizardTitle,
05096                  IDS_IMPORT_EMPTY_FILE);
05097                 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, 1);
05098                 ret = 1;
05099             }
05100             else
05101             {
05102                 LPWSTR fileName = HeapAlloc(GetProcessHeap(), 0,
05103                  (len + 1) * sizeof(WCHAR));
05104 
05105                 if (fileName)
05106                 {
05107                     SendMessageW(fileNameEdit, WM_GETTEXT, len + 1,
05108                      (LPARAM)fileName);
05109                     if (!import_validate_filename(hwnd, data, fileName))
05110                     {
05111                         HeapFree(GetProcessHeap(), 0, fileName);
05112                         SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, 1);
05113                         ret = 1;
05114                     }
05115                     else
05116                         data->fileName = fileName;
05117                 }
05118             }
05119             break;
05120         }
05121         }
05122         break;
05123     }
05124     case WM_COMMAND:
05125         switch (wp)
05126         {
05127         case IDC_IMPORT_BROWSE_FILE:
05128         {
05129             OPENFILENAMEW ofn;
05130             WCHAR fileBuf[MAX_PATH];
05131 
05132             data = (struct ImportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
05133             memset(&ofn, 0, sizeof(ofn));
05134             ofn.lStructSize = sizeof(ofn);
05135             ofn.hwndOwner = hwnd;
05136             ofn.lpstrFilter = make_import_file_filter(data->dwFlags);
05137             ofn.lpstrFile = fileBuf;
05138             ofn.nMaxFile = sizeof(fileBuf) / sizeof(fileBuf[0]);
05139             fileBuf[0] = 0;
05140             if (GetOpenFileNameW(&ofn))
05141                 SendMessageW(GetDlgItem(hwnd, IDC_IMPORT_FILENAME), WM_SETTEXT,
05142                  0, (LPARAM)ofn.lpstrFile);
05143             HeapFree(GetProcessHeap(), 0, (LPWSTR)ofn.lpstrFilter);
05144             break;
05145         }
05146         }
05147         break;
05148     }
05149     return ret;
05150 }
05151 
05152 static LRESULT CALLBACK import_store_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
05153  LPARAM lp)
05154 {
05155     LRESULT ret = 0;
05156     struct ImportWizData *data;
05157 
05158     switch (msg)
05159     {
05160     case WM_INITDIALOG:
05161     {
05162         PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp;
05163 
05164         data = (struct ImportWizData *)page->lParam;
05165         SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
05166         if (!data->hDestCertStore)
05167         {
05168             SendMessageW(GetDlgItem(hwnd, IDC_IMPORT_AUTO_STORE), BM_CLICK,
05169              0, 0);
05170             EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_STORE), FALSE);
05171             EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_BROWSE_STORE), FALSE);
05172             EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_SPECIFY_STORE), FALSE);
05173         }
05174         else
05175         {
05176             WCHAR storeTitle[MAX_STRING_LEN];
05177 
05178             SendMessageW(GetDlgItem(hwnd, IDC_IMPORT_SPECIFY_STORE), BM_CLICK,
05179              0, 0);
05180             EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_STORE), TRUE);
05181             EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_BROWSE_STORE), TRUE);
05182             EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_SPECIFY_STORE),
05183              !(data->dwFlags & CRYPTUI_WIZ_IMPORT_NO_CHANGE_DEST_STORE));
05184             LoadStringW(hInstance, IDS_IMPORT_DEST_DETERMINED,
05185              storeTitle, sizeof(storeTitle) / sizeof(storeTitle[0]));
05186             SendMessageW(GetDlgItem(hwnd, IDC_IMPORT_STORE), WM_SETTEXT,
05187              0, (LPARAM)storeTitle);
05188         }
05189         break;
05190     }
05191     case WM_NOTIFY:
05192     {
05193         NMHDR *hdr = (NMHDR *)lp;
05194 
05195         switch (hdr->code)
05196         {
05197         case PSN_SETACTIVE:
05198             PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0,
05199              PSWIZB_BACK | PSWIZB_NEXT);
05200             ret = TRUE;
05201             break;
05202         case PSN_WIZNEXT:
05203         {
05204             data = (struct ImportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
05205             if (IsDlgButtonChecked(hwnd, IDC_IMPORT_SPECIFY_STORE) &&
05206              !data->hDestCertStore)
05207             {
05208                 import_warning(data->dwFlags, hwnd, data->pwszWizardTitle,
05209                  IDS_IMPORT_SELECT_STORE);
05210                 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, 1);
05211                 ret = 1;
05212             }
05213             break;
05214         }
05215         }
05216         break;
05217     }
05218     case WM_COMMAND:
05219         switch (wp)
05220         {
05221         case IDC_IMPORT_AUTO_STORE:
05222             data = (struct ImportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
05223             data->autoDest = TRUE;
05224             EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_STORE), FALSE);
05225             EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_BROWSE_STORE), FALSE);
05226             break;
05227         case IDC_IMPORT_SPECIFY_STORE:
05228             data = (struct ImportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
05229             data->autoDest = FALSE;
05230             EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_STORE), TRUE);
05231             EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_BROWSE_STORE), TRUE);
05232             break;
05233         case IDC_IMPORT_BROWSE_STORE:
05234         {
05235             CRYPTUI_ENUM_SYSTEM_STORE_ARGS enumArgs = {
05236              CERT_SYSTEM_STORE_CURRENT_USER, NULL };
05237             CRYPTUI_ENUM_DATA enumData = { 0, NULL, 1, &enumArgs };
05238             CRYPTUI_SELECTSTORE_INFO_W selectInfo;
05239             HCERTSTORE store;
05240 
05241             data = (struct ImportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
05242             selectInfo.dwSize = sizeof(selectInfo);
05243             selectInfo.parent = hwnd;
05244             selectInfo.dwFlags = CRYPTUI_ENABLE_SHOW_PHYSICAL_STORE;
05245             selectInfo.pwszTitle = NULL;
05246             selectInfo.pwszText = NULL;
05247             selectInfo.pEnumData = &enumData;
05248             selectInfo.pfnSelectedStoreCallback = NULL;
05249             if ((store = CryptUIDlgSelectStoreW(&selectInfo)))
05250             {
05251                 WCHAR storeTitle[MAX_STRING_LEN];
05252 
05253                 LoadStringW(hInstance, IDS_IMPORT_DEST_DETERMINED,
05254                  storeTitle, sizeof(storeTitle) / sizeof(storeTitle[0]));
05255                 SendMessageW(GetDlgItem(hwnd, IDC_IMPORT_STORE), WM_SETTEXT,
05256                  0, (LPARAM)storeTitle);
05257                 data->hDestCertStore = store;
05258                 data->freeDest = TRUE;
05259             }
05260             break;
05261         }
05262         }
05263         break;
05264     }
05265     return ret;
05266 }
05267 
05268 static void show_import_details(HWND lv, struct ImportWizData *data)
05269 {
05270     WCHAR text[MAX_STRING_LEN];
05271     LVITEMW item;
05272     int contentID;
05273 
05274     item.mask = LVIF_TEXT;
05275     item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
05276     item.iSubItem = 0;
05277     LoadStringW(hInstance, IDS_IMPORT_STORE_SELECTION, text,
05278      sizeof(text)/ sizeof(text[0]));
05279     item.pszText = text;
05280     SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
05281     item.iSubItem = 1;
05282     if (data->autoDest)
05283         LoadStringW(hInstance, IDS_IMPORT_DEST_AUTOMATIC, text,
05284          sizeof(text)/ sizeof(text[0]));
05285     else
05286         LoadStringW(hInstance, IDS_IMPORT_DEST_DETERMINED, text,
05287          sizeof(text)/ sizeof(text[0]));
05288     SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
05289     item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
05290     item.iSubItem = 0;
05291     LoadStringW(hInstance, IDS_IMPORT_CONTENT, text,
05292      sizeof(text)/ sizeof(text[0]));
05293     SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
05294     switch (data->contentType)
05295     {
05296     case CERT_QUERY_CONTENT_CERT:
05297     case CERT_QUERY_CONTENT_SERIALIZED_CERT:
05298         contentID = IDS_IMPORT_CONTENT_CERT;
05299         break;
05300     case CERT_QUERY_CONTENT_CRL:
05301     case CERT_QUERY_CONTENT_SERIALIZED_CRL:
05302         contentID = IDS_IMPORT_CONTENT_CRL;
05303         break;
05304     case CERT_QUERY_CONTENT_CTL:
05305     case CERT_QUERY_CONTENT_SERIALIZED_CTL:
05306         contentID = IDS_IMPORT_CONTENT_CTL;
05307         break;
05308     case CERT_QUERY_CONTENT_PKCS7_SIGNED:
05309         contentID = IDS_IMPORT_CONTENT_CMS;
05310         break;
05311     case CERT_QUERY_CONTENT_FLAG_PFX:
05312         contentID = IDS_IMPORT_CONTENT_PFX;
05313         break;
05314     default:
05315         contentID = IDS_IMPORT_CONTENT_STORE;
05316         break;
05317     }
05318     LoadStringW(hInstance, contentID, text, sizeof(text)/ sizeof(text[0]));
05319     item.iSubItem = 1;
05320     SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
05321     if (data->fileName)
05322     {
05323         item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
05324         item.iSubItem = 0;
05325         LoadStringW(hInstance, IDS_IMPORT_FILE, text,
05326          sizeof(text)/ sizeof(text[0]));
05327         SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
05328         item.iSubItem = 1;
05329         item.pszText = data->fileName;
05330         SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
05331     }
05332 }
05333 
05334 static BOOL do_import(DWORD dwFlags, HWND hwndParent, LPCWSTR pwszWizardTitle,
05335  PCCRYPTUI_WIZ_IMPORT_SRC_INFO pImportSrc, HCERTSTORE hDestCertStore)
05336 {
05337     BOOL ret;
05338 
05339     switch (pImportSrc->dwSubjectChoice)
05340     {
05341     case CRYPTUI_WIZ_IMPORT_SUBJECT_FILE:
05342         ret = import_file(dwFlags, hwndParent, pwszWizardTitle,
05343          pImportSrc->u.pwszFileName, hDestCertStore);
05344         break;
05345     case CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_CONTEXT:
05346         if ((ret = check_context_type(dwFlags, CERT_QUERY_CONTENT_CERT)))
05347             ret = import_cert(pImportSrc->u.pCertContext, hDestCertStore);
05348         else
05349             import_warn_type_mismatch(dwFlags, hwndParent, pwszWizardTitle);
05350         break;
05351     case CRYPTUI_WIZ_IMPORT_SUBJECT_CRL_CONTEXT:
05352         if ((ret = check_context_type(dwFlags, CERT_QUERY_CONTENT_CRL)))
05353             ret = import_crl(pImportSrc->u.pCRLContext, hDestCertStore);
05354         else
05355             import_warn_type_mismatch(dwFlags, hwndParent, pwszWizardTitle);
05356         break;
05357     case CRYPTUI_WIZ_IMPORT_SUBJECT_CTL_CONTEXT:
05358         if ((ret = check_context_type(dwFlags, CERT_QUERY_CONTENT_CTL)))
05359             ret = import_ctl(pImportSrc->u.pCTLContext, hDestCertStore);
05360         else
05361             import_warn_type_mismatch(dwFlags, hwndParent, pwszWizardTitle);
05362         break;
05363     case CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_STORE:
05364         ret = import_store(dwFlags, hwndParent, pwszWizardTitle,
05365          pImportSrc->u.hCertStore, hDestCertStore);
05366         break;
05367     default:
05368         WARN("unknown source type: %u\n", pImportSrc->dwSubjectChoice);
05369         SetLastError(E_INVALIDARG);
05370         ret = FALSE;
05371     }
05372     return ret;
05373 }
05374 
05375 static LRESULT CALLBACK import_finish_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
05376  LPARAM lp)
05377 {
05378     LRESULT ret = 0;
05379     struct ImportWizData *data;
05380 
05381     switch (msg)
05382     {
05383     case WM_INITDIALOG:
05384     {
05385         PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp;
05386         HWND lv = GetDlgItem(hwnd, IDC_IMPORT_SETTINGS);
05387         RECT rc;
05388         LVCOLUMNW column;
05389 
05390         data = (struct ImportWizData *)page->lParam;
05391         SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
05392         SendMessageW(GetDlgItem(hwnd, IDC_IMPORT_TITLE), WM_SETFONT,
05393          (WPARAM)data->titleFont, TRUE);
05394         GetWindowRect(lv, &rc);
05395         column.mask = LVCF_WIDTH;
05396         column.cx = (rc.right - rc.left) / 2 - 2;
05397         SendMessageW(lv, LVM_INSERTCOLUMNW, 0, (LPARAM)&column);
05398         SendMessageW(lv, LVM_INSERTCOLUMNW, 1, (LPARAM)&column);
05399         show_import_details(lv, data);
05400         break;
05401     }
05402     case WM_NOTIFY:
05403     {
05404         NMHDR *hdr = (NMHDR *)lp;
05405 
05406         switch (hdr->code)
05407         {
05408         case PSN_SETACTIVE:
05409         {
05410             HWND lv = GetDlgItem(hwnd, IDC_IMPORT_SETTINGS);
05411 
05412             data = (struct ImportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
05413             SendMessageW(lv, LVM_DELETEALLITEMS, 0, 0);
05414             show_import_details(lv, data);
05415             PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0,
05416              PSWIZB_BACK | PSWIZB_FINISH);
05417             ret = TRUE;
05418             break;
05419         }
05420         case PSN_WIZFINISH:
05421         {
05422             data = (struct ImportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
05423             if ((data->success = do_import(data->dwFlags, hwnd,
05424              data->pwszWizardTitle, &data->importSrc, data->hDestCertStore)))
05425             {
05426                 WCHAR title[MAX_STRING_LEN], message[MAX_STRING_LEN];
05427                 LPCWSTR pTitle;
05428 
05429                 if (data->pwszWizardTitle)
05430                     pTitle = data->pwszWizardTitle;
05431                 else
05432                 {
05433                     LoadStringW(hInstance, IDS_IMPORT_WIZARD, title,
05434                      sizeof(title) / sizeof(title[0]));
05435                     pTitle = title;
05436                 }
05437                 LoadStringW(hInstance, IDS_IMPORT_SUCCEEDED, message,
05438                  sizeof(message) / sizeof(message[0]));
05439                 MessageBoxW(hwnd, message, pTitle, MB_OK);
05440             }
05441             else
05442                 import_warning(data->dwFlags, hwnd, data->pwszWizardTitle,
05443                  IDS_IMPORT_FAILED);
05444             break;
05445         }
05446         }
05447         break;
05448     }
05449     }
05450     return ret;
05451 }
05452 
05453 static BOOL show_import_ui(DWORD dwFlags, HWND hwndParent,
05454  LPCWSTR pwszWizardTitle, PCCRYPTUI_WIZ_IMPORT_SRC_INFO pImportSrc,
05455  HCERTSTORE hDestCertStore)
05456 {
05457     PROPSHEETHEADERW hdr;
05458     PROPSHEETPAGEW pages[4];
05459     struct ImportWizData data;
05460     int nPages = 0;
05461 
05462     data.dwFlags = dwFlags;
05463     data.pwszWizardTitle = pwszWizardTitle;
05464     if (pImportSrc)
05465     {
05466         memcpy(&data.importSrc, pImportSrc, sizeof(data.importSrc));
05467         data.fileName = (LPWSTR)pImportSrc->u.pwszFileName;
05468     }
05469     else
05470     {
05471         memset(&data.importSrc, 0, sizeof(data.importSrc));
05472         data.fileName = NULL;
05473     }
05474     data.freeSource = FALSE;
05475     data.hDestCertStore = hDestCertStore;
05476     data.freeDest = FALSE;
05477     data.autoDest = TRUE;
05478     data.success = TRUE;
05479 
05480     memset(pages, 0, sizeof(pages));
05481 
05482     pages[nPages].dwSize = sizeof(pages[0]);
05483     pages[nPages].hInstance = hInstance;
05484     pages[nPages].u.pszTemplate = MAKEINTRESOURCEW(IDD_IMPORT_WELCOME);
05485     pages[nPages].pfnDlgProc = import_welcome_dlg_proc;
05486     pages[nPages].dwFlags = PSP_HIDEHEADER;
05487     pages[nPages].lParam = (LPARAM)&data;
05488     nPages++;
05489 
05490     if (!pImportSrc ||
05491      pImportSrc->dwSubjectChoice == CRYPTUI_WIZ_IMPORT_SUBJECT_FILE)
05492     {
05493         pages[nPages].dwSize = sizeof(pages[0]);
05494         pages[nPages].hInstance = hInstance;
05495         pages[nPages].u.pszTemplate = MAKEINTRESOURCEW(IDD_IMPORT_FILE);
05496         pages[nPages].pfnDlgProc = import_file_dlg_proc;
05497         pages[nPages].dwFlags = PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
05498         pages[nPages].pszHeaderTitle = MAKEINTRESOURCEW(IDS_IMPORT_FILE_TITLE);
05499         pages[nPages].pszHeaderSubTitle =
05500          MAKEINTRESOURCEW(IDS_IMPORT_FILE_SUBTITLE);
05501         pages[nPages].lParam = (LPARAM)&data;
05502         nPages++;
05503     }
05504     else
05505     {
05506         switch (pImportSrc->dwSubjectChoice)
05507         {
05508         case CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_CONTEXT:
05509             data.contentType = CERT_QUERY_CONTENT_CERT;
05510             break;
05511         case CRYPTUI_WIZ_IMPORT_SUBJECT_CRL_CONTEXT:
05512             data.contentType = CERT_QUERY_CONTENT_CRL;
05513             break;
05514         case CRYPTUI_WIZ_IMPORT_SUBJECT_CTL_CONTEXT:
05515             data.contentType = CERT_QUERY_CONTENT_CTL;
05516             break;
05517         case CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_STORE:
05518             data.contentType = CERT_QUERY_CONTENT_SERIALIZED_STORE;
05519             break;
05520         }
05521     }
05522 
05523     pages[nPages].dwSize = sizeof(pages[0]);
05524     pages[nPages].hInstance = hInstance;
05525     pages[nPages].u.pszTemplate = MAKEINTRESOURCEW(IDD_IMPORT_STORE);
05526     pages[nPages].pfnDlgProc = import_store_dlg_proc;
05527     pages[nPages].dwFlags = PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
05528     pages[nPages].pszHeaderTitle = MAKEINTRESOURCEW(IDS_IMPORT_STORE_TITLE);
05529     pages[nPages].pszHeaderSubTitle =
05530      MAKEINTRESOURCEW(IDS_IMPORT_STORE_SUBTITLE);
05531     pages[nPages].lParam = (LPARAM)&data;
05532     nPages++;
05533 
05534     pages[nPages].dwSize = sizeof(pages[0]);
05535     pages[nPages].hInstance = hInstance;
05536     pages[nPages].u.pszTemplate = MAKEINTRESOURCEW(IDD_IMPORT_FINISH);
05537     pages[nPages].pfnDlgProc = import_finish_dlg_proc;
05538     pages[nPages].dwFlags = PSP_HIDEHEADER;
05539     pages[nPages].lParam = (LPARAM)&data;
05540     nPages++;
05541 
05542     memset(&hdr, 0, sizeof(hdr));
05543     hdr.dwSize = sizeof(hdr);
05544     hdr.hwndParent = hwndParent;
05545     hdr.dwFlags = PSH_PROPSHEETPAGE | PSH_WIZARD97_NEW | PSH_HEADER |
05546      PSH_WATERMARK;
05547     hdr.hInstance = hInstance;
05548     if (pwszWizardTitle)
05549         hdr.pszCaption = pwszWizardTitle;
05550     else
05551         hdr.pszCaption = MAKEINTRESOURCEW(IDS_IMPORT_WIZARD);
05552     hdr.u3.ppsp = pages;
05553     hdr.nPages = nPages;
05554     hdr.u4.pszbmWatermark = MAKEINTRESOURCEW(IDB_CERT_WATERMARK);
05555     hdr.u5.pszbmHeader = MAKEINTRESOURCEW(IDB_CERT_HEADER);
05556     PropertySheetW(&hdr);
05557     if (data.fileName != data.importSrc.u.pwszFileName)
05558         HeapFree(GetProcessHeap(), 0, data.fileName);
05559     if (data.freeSource &&
05560      data.importSrc.dwSubjectChoice == CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_STORE)
05561         CertCloseStore(data.importSrc.u.hCertStore, 0);
05562     DeleteObject(data.titleFont);
05563     return data.success;
05564 }
05565 
05566 BOOL WINAPI CryptUIWizImport(DWORD dwFlags, HWND hwndParent, LPCWSTR pwszWizardTitle,
05567                              PCCRYPTUI_WIZ_IMPORT_SRC_INFO pImportSrc, HCERTSTORE hDestCertStore)
05568 {
05569     BOOL ret;
05570 
05571     TRACE("(0x%08x, %p, %s, %p, %p)\n", dwFlags, hwndParent, debugstr_w(pwszWizardTitle),
05572           pImportSrc, hDestCertStore);
05573 
05574     if (pImportSrc &&
05575      pImportSrc->dwSize != sizeof(CRYPTUI_WIZ_IMPORT_SRC_INFO))
05576     {
05577         SetLastError(E_INVALIDARG);
05578         return FALSE;
05579     }
05580 
05581     if (!(dwFlags & CRYPTUI_WIZ_NO_UI))
05582         ret = show_import_ui(dwFlags, hwndParent, pwszWizardTitle, pImportSrc,
05583          hDestCertStore);
05584     else if (pImportSrc)
05585         ret = do_import(dwFlags, hwndParent, pwszWizardTitle, pImportSrc,
05586          hDestCertStore);
05587     else
05588     {
05589         /* Can't have no UI without specifying source */
05590         SetLastError(E_INVALIDARG);
05591         ret = FALSE;
05592     }
05593 
05594     return ret;
05595 }
05596 
05597 struct ExportWizData
05598 {
05599     HFONT titleFont;
05600     DWORD dwFlags;
05601     LPCWSTR pwszWizardTitle;
05602     CRYPTUI_WIZ_EXPORT_INFO exportInfo;
05603     CRYPTUI_WIZ_EXPORT_CERTCONTEXT_INFO contextInfo;
05604     BOOL freePassword;
05605     PCRYPT_KEY_PROV_INFO keyProvInfo;
05606     BOOL deleteKeys;
05607     LPWSTR fileName;
05608     HANDLE file;
05609     BOOL success;
05610 };
05611 
05612 static LRESULT CALLBACK export_welcome_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
05613  LPARAM lp)
05614 {
05615     LRESULT ret = 0;
05616 
05617     switch (msg)
05618     {
05619     case WM_INITDIALOG:
05620     {
05621         struct ExportWizData *data;
05622         PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp;
05623         WCHAR fontFace[MAX_STRING_LEN];
05624         HDC hDC = GetDC(hwnd);
05625         int height;
05626 
05627         data = (struct ExportWizData *)page->lParam;
05628         LoadStringW(hInstance, IDS_WIZARD_TITLE_FONT, fontFace,
05629          sizeof(fontFace) / sizeof(fontFace[0]));
05630         height = -MulDiv(12, GetDeviceCaps(hDC, LOGPIXELSY), 72);
05631         data->titleFont = CreateFontW(height, 0, 0, 0, FW_BOLD, 0, 0, 0,
05632          DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
05633          DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, fontFace);
05634         SendMessageW(GetDlgItem(hwnd, IDC_EXPORT_TITLE), WM_SETFONT,
05635          (WPARAM)data->titleFont, TRUE);
05636         ReleaseDC(hwnd, hDC);
05637         break;
05638     }
05639     case WM_NOTIFY:
05640     {
05641         NMHDR *hdr = (NMHDR *)lp;
05642 
05643         switch (hdr->code)
05644         {
05645         case PSN_SETACTIVE:
05646             PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0, PSWIZB_NEXT);
05647             ret = TRUE;
05648             break;
05649         }
05650         break;
05651     }
05652     }
05653     return ret;
05654 }
05655 
05656 static PCRYPT_KEY_PROV_INFO export_get_private_key_info(PCCERT_CONTEXT cert)
05657 {
05658     PCRYPT_KEY_PROV_INFO info = NULL;
05659     DWORD size;
05660 
05661     if (CertGetCertificateContextProperty(cert, CERT_KEY_PROV_INFO_PROP_ID,
05662      NULL, &size))
05663     {
05664         info = HeapAlloc(GetProcessHeap(), 0, size);
05665         if (info)
05666         {
05667             if (!CertGetCertificateContextProperty(cert,
05668              CERT_KEY_PROV_INFO_PROP_ID, info, &size))
05669             {
05670                 HeapFree(GetProcessHeap(), 0, info);
05671                 info = NULL;
05672             }
05673         }
05674     }
05675     return info;
05676 }
05677 
05678 static BOOL export_acquire_private_key(const CRYPT_KEY_PROV_INFO *info,
05679  HCRYPTPROV *phProv)
05680 {
05681     BOOL ret;
05682 
05683     ret = CryptAcquireContextW(phProv, info->pwszContainerName,
05684      info->pwszProvName, info->dwProvType, 0);
05685     if (ret)
05686     {
05687         DWORD i;
05688 
05689         for (i = 0; i < info->cProvParam; i++)
05690             CryptSetProvParam(*phProv, info->rgProvParam[i].dwParam,
05691              info->rgProvParam[i].pbData, info->rgProvParam[i].dwFlags);
05692     }
05693     return ret;
05694 }
05695 
05696 static BOOL export_is_key_exportable(HCRYPTPROV hProv, DWORD keySpec)
05697 {
05698     BOOL ret;
05699     HCRYPTKEY key;
05700 
05701     if ((ret = CryptGetUserKey(hProv, keySpec, &key)))
05702     {
05703         DWORD permissions, size = sizeof(permissions);
05704 
05705         if ((ret = CryptGetKeyParam(key, KP_PERMISSIONS, (BYTE *)&permissions,
05706          &size, 0)) && !(permissions & CRYPT_EXPORT))
05707             ret = FALSE;
05708         CryptDestroyKey(key);
05709     }
05710     return ret;
05711 }
05712 
05713 static LRESULT CALLBACK export_private_key_dlg_proc(HWND hwnd, UINT msg,
05714  WPARAM wp, LPARAM lp)
05715 {
05716     LRESULT ret = 0;
05717     struct ExportWizData *data;
05718 
05719     switch (msg)
05720     {
05721     case WM_INITDIALOG:
05722     {
05723         PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp;
05724         PCRYPT_KEY_PROV_INFO info;
05725         HCRYPTPROV hProv = 0;
05726         int errorID = 0;
05727 
05728         data = (struct ExportWizData *)page->lParam;
05729         SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
05730         /* Get enough information about a key to see whether it's exportable.
05731          */
05732         if (!(info = export_get_private_key_info(
05733          data->exportInfo.u.pCertContext)))
05734             errorID = IDS_EXPORT_PRIVATE_KEY_UNAVAILABLE;
05735         else if (!export_acquire_private_key(info, &hProv))
05736             errorID = IDS_EXPORT_PRIVATE_KEY_UNAVAILABLE;
05737         else if (!export_is_key_exportable(hProv, info->dwKeySpec))
05738             errorID = IDS_EXPORT_PRIVATE_KEY_NON_EXPORTABLE;
05739 
05740         if (errorID)
05741         {
05742             WCHAR error[MAX_STRING_LEN];
05743 
05744             LoadStringW(hInstance, errorID, error,
05745              sizeof(error) / sizeof(error[0]));
05746             SendMessageW(GetDlgItem(hwnd, IDC_EXPORT_PRIVATE_KEY_UNAVAILABLE),
05747              WM_SETTEXT, 0, (LPARAM)error);
05748             EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_PRIVATE_KEY_YES), FALSE);
05749         }
05750         else
05751             data->keyProvInfo = info;
05752         if (hProv)
05753             CryptReleaseContext(hProv, 0);
05754         SendMessageW(GetDlgItem(hwnd, IDC_EXPORT_PRIVATE_KEY_NO), BM_CLICK,
05755          0, 0);
05756         break;
05757     }
05758     case WM_NOTIFY:
05759     {
05760         NMHDR *hdr = (NMHDR *)lp;
05761 
05762         switch (hdr->code)
05763         {
05764         case PSN_SETACTIVE:
05765             PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0,
05766              PSWIZB_BACK | PSWIZB_NEXT);
05767             ret = TRUE;
05768             break;
05769         case PSN_WIZNEXT:
05770             data = (struct ExportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
05771             if (IsDlgButtonChecked(hwnd, IDC_EXPORT_PRIVATE_KEY_NO))
05772             {
05773                 data->contextInfo.dwExportFormat =
05774                  CRYPTUI_WIZ_EXPORT_FORMAT_DER;
05775                 data->contextInfo.fExportPrivateKeys = FALSE;
05776             }
05777             else
05778             {
05779                 data->contextInfo.dwExportFormat =
05780                  CRYPTUI_WIZ_EXPORT_FORMAT_PFX;
05781                 data->contextInfo.fExportPrivateKeys = TRUE;
05782             }
05783             break;
05784         }
05785         break;
05786     }
05787     }
05788     return ret;
05789 }
05790 
05791 static BOOL export_info_has_private_key(PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo)
05792 {
05793     BOOL ret = FALSE;
05794 
05795     if (pExportInfo->dwSubjectChoice == CRYPTUI_WIZ_EXPORT_CERT_CONTEXT)
05796     {
05797         DWORD size;
05798 
05799         /* If there's a CRYPT_KEY_PROV_INFO set for this cert, assume the
05800          * cert has a private key.
05801          */
05802         if (CertGetCertificateContextProperty(pExportInfo->u.pCertContext,
05803          CERT_KEY_PROV_INFO_PROP_ID, NULL, &size))
05804             ret = TRUE;
05805     }
05806     return ret;
05807 }
05808 
05809 static void export_format_enable_controls(HWND hwnd, const struct ExportWizData *data)
05810 {
05811     int defaultFormatID;
05812 
05813     switch (data->contextInfo.dwExportFormat)
05814     {
05815     case CRYPTUI_WIZ_EXPORT_FORMAT_BASE64:
05816         defaultFormatID = IDC_EXPORT_FORMAT_BASE64;
05817         break;
05818     case CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7:
05819         defaultFormatID = IDC_EXPORT_FORMAT_CMS;
05820         break;
05821     case CRYPTUI_WIZ_EXPORT_FORMAT_PFX:
05822         defaultFormatID = IDC_EXPORT_FORMAT_PFX;
05823         break;
05824     default:
05825         defaultFormatID = IDC_EXPORT_FORMAT_DER;
05826     }
05827     SendMessageW(GetDlgItem(hwnd, defaultFormatID), BM_CLICK, 0, 0);
05828     if (defaultFormatID == IDC_EXPORT_FORMAT_PFX)
05829     {
05830         EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_FORMAT_DER), FALSE);
05831         EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_FORMAT_BASE64), FALSE);
05832         EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_FORMAT_CMS), FALSE);
05833         EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_FORMAT_PFX), TRUE);
05834     }
05835     else
05836     {
05837         EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_FORMAT_DER), TRUE);
05838         EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_FORMAT_BASE64), TRUE);
05839         EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_FORMAT_CMS), TRUE);
05840         EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_FORMAT_PFX), FALSE);
05841     }
05842 }
05843 
05844 static LRESULT CALLBACK export_format_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
05845  LPARAM lp)
05846 {
05847     LRESULT ret = 0;
05848     struct ExportWizData *data;
05849 
05850     switch (msg)
05851     {
05852     case WM_INITDIALOG:
05853     {
05854         PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp;
05855 
05856         data = (struct ExportWizData *)page->lParam;
05857         SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
05858         export_format_enable_controls(hwnd, data);
05859         break;
05860     }
05861     case WM_NOTIFY:
05862     {
05863         NMHDR *hdr = (NMHDR *)lp;
05864 
05865         switch (hdr->code)
05866         {
05867         case PSN_SETACTIVE:
05868             PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0,
05869              PSWIZB_BACK | PSWIZB_NEXT);
05870             data = (struct ExportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
05871             export_format_enable_controls(hwnd, data);
05872             ret = TRUE;
05873             break;
05874         case PSN_WIZNEXT:
05875         {
05876             BOOL skipPasswordPage = TRUE;
05877 
05878             data = (struct ExportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
05879             if (IsDlgButtonChecked(hwnd, IDC_EXPORT_FORMAT_DER))
05880                 data->contextInfo.dwExportFormat =
05881                  CRYPTUI_WIZ_EXPORT_FORMAT_DER;
05882             else if (IsDlgButtonChecked(hwnd, IDC_EXPORT_FORMAT_BASE64))
05883                 data->contextInfo.dwExportFormat =
05884                  CRYPTUI_WIZ_EXPORT_FORMAT_BASE64;
05885             else if (IsDlgButtonChecked(hwnd, IDC_EXPORT_FORMAT_CMS))
05886             {
05887                 data->contextInfo.dwExportFormat =
05888                  CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7;
05889                 if (IsDlgButtonChecked(hwnd, IDC_EXPORT_CMS_INCLUDE_CHAIN))
05890                     data->contextInfo.fExportChain =
05891                      CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7;
05892             }
05893             else
05894             {
05895                 data->contextInfo.dwExportFormat =
05896                  CRYPTUI_WIZ_EXPORT_FORMAT_PFX;
05897                 if (IsDlgButtonChecked(hwnd, IDC_EXPORT_PFX_INCLUDE_CHAIN))
05898                     data->contextInfo.fExportChain = TRUE;
05899                 if (IsDlgButtonChecked(hwnd, IDC_EXPORT_PFX_STRONG_ENCRYPTION))
05900                     data->contextInfo.fStrongEncryption = TRUE;
05901                 if (IsDlgButtonChecked(hwnd, IDC_EXPORT_PFX_DELETE_PRIVATE_KEY))
05902                     data->deleteKeys = TRUE;
05903                 skipPasswordPage = FALSE;
05904             }
05905             SetWindowLongPtrW(hwnd, DWLP_MSGRESULT,
05906              skipPasswordPage ? IDD_EXPORT_FILE : 0);
05907             ret = 1;
05908             break;
05909         }
05910         }
05911         break;
05912     }
05913     case WM_COMMAND:
05914         switch (HIWORD(wp))
05915         {
05916         case BN_CLICKED:
05917             switch (LOWORD(wp))
05918             {
05919             case IDC_EXPORT_FORMAT_DER:
05920             case IDC_EXPORT_FORMAT_BASE64:
05921                 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_CMS_INCLUDE_CHAIN),
05922                  FALSE);
05923                 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_PFX_INCLUDE_CHAIN),
05924                  FALSE);
05925                 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_PFX_STRONG_ENCRYPTION),
05926                  FALSE);
05927                 EnableWindow(GetDlgItem(hwnd,
05928                  IDC_EXPORT_PFX_DELETE_PRIVATE_KEY), FALSE);
05929                 break;
05930             case IDC_EXPORT_FORMAT_CMS:
05931                 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_CMS_INCLUDE_CHAIN),
05932                  TRUE);
05933                 break;
05934             case IDC_EXPORT_FORMAT_PFX:
05935                 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_PFX_INCLUDE_CHAIN),
05936                  TRUE);
05937                 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_PFX_STRONG_ENCRYPTION),
05938                  TRUE);
05939                 EnableWindow(GetDlgItem(hwnd,
05940                  IDC_EXPORT_PFX_DELETE_PRIVATE_KEY), TRUE);
05941                 break;
05942             }
05943             break;
05944         }
05945         break;
05946     }
05947     return ret;
05948 }
05949 
05950 static void export_password_mismatch(HWND hwnd, const struct ExportWizData *data)
05951 {
05952     WCHAR title[MAX_STRING_LEN], error[MAX_STRING_LEN];
05953     LPCWSTR pTitle;
05954 
05955     if (data->pwszWizardTitle)
05956         pTitle = data->pwszWizardTitle;
05957     else
05958     {
05959         LoadStringW(hInstance, IDS_EXPORT_WIZARD, title,
05960          sizeof(title) / sizeof(title[0]));
05961         pTitle = title;
05962     }
05963     LoadStringW(hInstance, IDS_EXPORT_PASSWORD_MISMATCH, error,
05964      sizeof(error) / sizeof(error[0]));
05965     MessageBoxW(hwnd, error, pTitle, MB_ICONERROR | MB_OK);
05966     SetFocus(GetDlgItem(hwnd, IDC_EXPORT_PASSWORD));
05967 }
05968 
05969 static LRESULT CALLBACK export_password_dlg_proc(HWND hwnd, UINT msg,
05970  WPARAM wp, LPARAM lp)
05971 {
05972     LRESULT ret = 0;
05973     struct ExportWizData *data;
05974 
05975     switch (msg)
05976     {
05977     case WM_INITDIALOG:
05978     {
05979         PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp;
05980 
05981         data = (struct ExportWizData *)page->lParam;
05982         SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
05983         break;
05984     }
05985     case WM_NOTIFY:
05986     {
05987         NMHDR *hdr = (NMHDR *)lp;
05988 
05989         switch (hdr->code)
05990         {
05991         case PSN_SETACTIVE:
05992             PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0,
05993              PSWIZB_BACK | PSWIZB_NEXT);
05994             ret = TRUE;
05995             break;
05996         case PSN_WIZNEXT:
05997         {
05998             HWND passwordEdit = GetDlgItem(hwnd, IDC_EXPORT_PASSWORD);
05999             HWND passwordConfirmEdit = GetDlgItem(hwnd,
06000              IDC_EXPORT_PASSWORD_CONFIRM);
06001             DWORD passwordLen = SendMessageW(passwordEdit, WM_GETTEXTLENGTH,
06002              0, 0);
06003             DWORD passwordConfirmLen = SendMessageW(passwordConfirmEdit,
06004              WM_GETTEXTLENGTH, 0, 0);
06005 
06006             data = (struct ExportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
06007             if (!passwordLen && !passwordConfirmLen)
06008                 data->contextInfo.pwszPassword = NULL;
06009             else if (passwordLen != passwordConfirmLen)
06010             {
06011                 export_password_mismatch(hwnd, data);
06012                 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, 1);
06013                 ret = 1;
06014             }
06015             else
06016             {
06017                 LPWSTR password = HeapAlloc(GetProcessHeap(), 0,
06018                  (passwordLen + 1) * sizeof(WCHAR));
06019                 LPWSTR passwordConfirm = HeapAlloc(GetProcessHeap(), 0,
06020                  (passwordConfirmLen + 1) * sizeof(WCHAR));
06021                 BOOL freePassword = TRUE;
06022 
06023                 if (password && passwordConfirm)
06024                 {
06025                     SendMessageW(passwordEdit, WM_GETTEXT, passwordLen + 1,
06026                      (LPARAM)password);
06027                     SendMessageW(passwordConfirmEdit, WM_GETTEXT,
06028                      passwordConfirmLen + 1, (LPARAM)passwordConfirm);
06029                     if (strcmpW(password, passwordConfirm))
06030                     {
06031                         export_password_mismatch(hwnd, data);
06032                         SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, 1);
06033                         ret = 1;
06034                     }
06035                     else
06036                     {
06037                         data->contextInfo.pwszPassword = password;
06038                         freePassword = FALSE;
06039                         data->freePassword = TRUE;
06040                     }
06041                 }
06042                 if (freePassword)
06043                     HeapFree(GetProcessHeap(), 0, password);
06044                 HeapFree(GetProcessHeap(), 0, passwordConfirm);
06045             }
06046             break;
06047         }
06048         }
06049         break;
06050     }
06051     }
06052     return ret;
06053 }
06054 
06055 static LPWSTR export_append_extension(const struct ExportWizData *data,
06056  LPWSTR fileName)
06057 {
06058     static const WCHAR cer[] = { '.','c','e','r',0 };
06059     static const WCHAR crl[] = { '.','c','r','l',0 };
06060     static const WCHAR ctl[] = { '.','c','t','l',0 };
06061     static const WCHAR p7b[] = { '.','p','7','b',0 };
06062     static const WCHAR pfx[] = { '.','p','f','x',0 };
06063     static const WCHAR sst[] = { '.','s','s','t',0 };
06064     LPCWSTR extension;
06065     LPWSTR dot;
06066     BOOL appendExtension;
06067 
06068     switch (data->contextInfo.dwExportFormat)
06069     {
06070     case CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7:
06071         extension = p7b;
06072         break;
06073     case CRYPTUI_WIZ_EXPORT_FORMAT_PFX:
06074         extension = pfx;
06075         break;
06076     default:
06077         switch (data->exportInfo.dwSubjectChoice)
06078         {
06079         case CRYPTUI_WIZ_EXPORT_CRL_CONTEXT:
06080             extension = crl;
06081             break;
06082         case CRYPTUI_WIZ_EXPORT_CTL_CONTEXT:
06083             extension = ctl;
06084             break;
06085         case CRYPTUI_WIZ_EXPORT_CERT_STORE:
06086             extension = sst;
06087             break;
06088         default:
06089             extension = cer;
06090         }
06091     }
06092     dot = strrchrW(fileName, '.');
06093     if (dot)
06094         appendExtension = strcmpiW(dot, extension) != 0;
06095     else
06096         appendExtension = TRUE;
06097     if (appendExtension)
06098     {
06099         fileName = HeapReAlloc(GetProcessHeap(), 0, fileName,
06100          (strlenW(fileName) + strlenW(extension) + 1) * sizeof(WCHAR));
06101         if (fileName)
06102             strcatW(fileName, extension);
06103     }
06104     return fileName;
06105 }
06106 
06107 static BOOL export_validate_filename(HWND hwnd, struct ExportWizData *data,
06108  LPCWSTR fileName)
06109 {
06110     HANDLE file;
06111     BOOL tryCreate = TRUE, forceCreate = FALSE, ret = FALSE;
06112 
06113     file = CreateFileW(fileName, GENERIC_WRITE,
06114      FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
06115     if (file != INVALID_HANDLE_VALUE)
06116     {
06117         WCHAR warning[MAX_STRING_LEN], title[MAX_STRING_LEN];
06118         LPCWSTR pTitle;
06119 
06120         if (data->pwszWizardTitle)
06121             pTitle = data->pwszWizardTitle;
06122         else
06123         {
06124             LoadStringW(hInstance, IDS_EXPORT_WIZARD, title,
06125              sizeof(title) / sizeof(title[0]));
06126             pTitle = title;
06127         }
06128         LoadStringW(hInstance, IDS_EXPORT_FILE_EXISTS, warning,
06129          sizeof(warning) / sizeof(warning[0]));
06130         if (MessageBoxW(hwnd, warning, pTitle, MB_YESNO) == IDYES)
06131             forceCreate = TRUE;
06132         else
06133             tryCreate = FALSE;
06134         CloseHandle(file);
06135     }
06136     if (tryCreate)
06137     {
06138         file = CreateFileW(fileName, GENERIC_WRITE,
06139          FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
06140          forceCreate ? CREATE_ALWAYS : CREATE_NEW,
06141          0, NULL);
06142         if (file != INVALID_HANDLE_VALUE)
06143         {
06144             data->file = file;
06145             ret = TRUE;
06146         }
06147         else
06148         {
06149             WCHAR title[MAX_STRING_LEN], error[MAX_STRING_LEN];
06150             LPCWSTR pTitle;
06151             LPWSTR msgBuf, fullError;
06152 
06153             if (data->pwszWizardTitle)
06154                 pTitle = data->pwszWizardTitle;
06155             else
06156             {
06157                 LoadStringW(hInstance, IDS_EXPORT_WIZARD, title,
06158                  sizeof(title) / sizeof(title[0]));
06159                 pTitle = title;
06160             }
06161             LoadStringW(hInstance, IDS_IMPORT_OPEN_FAILED, error,
06162              sizeof(error) / sizeof(error[0]));
06163             FormatMessageW(
06164              FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL,
06165              GetLastError(), 0, (LPWSTR) &msgBuf, 0, NULL);
06166             fullError = HeapAlloc(GetProcessHeap(), 0,
06167              (strlenW(error) + strlenW(fileName) + strlenW(msgBuf) + 3)
06168              * sizeof(WCHAR));
06169             if (fullError)
06170             {
06171                 LPWSTR ptr = fullError;
06172 
06173                 strcpyW(ptr, error);
06174                 ptr += strlenW(error);
06175                 strcpyW(ptr, fileName);
06176                 ptr += strlenW(fileName);
06177                 *ptr++ = ':';
06178                 *ptr++ = '\n';
06179                 strcpyW(ptr, msgBuf);
06180                 MessageBoxW(hwnd, fullError, pTitle, MB_ICONERROR | MB_OK);
06181                 HeapFree(GetProcessHeap(), 0, fullError);
06182             }
06183             LocalFree(msgBuf);
06184         }
06185     }
06186     return ret;
06187 }
06188 
06189 static const WCHAR export_filter_cert[] = { '*','.','c','e','r',0 };
06190 static const WCHAR export_filter_crl[] = { '*','.','c','r','l',0 };
06191 static const WCHAR export_filter_ctl[] = { '*','.','s','t','l',0 };
06192 static const WCHAR export_filter_cms[] = { '*','.','p','7','b',0 };
06193 static const WCHAR export_filter_pfx[] = { '*','.','p','f','x',0 };
06194 static const WCHAR export_filter_sst[] = { '*','.','s','s','t',0 };
06195 
06196 static WCHAR *make_export_file_filter(DWORD exportFormat, DWORD subjectChoice)
06197 {
06198     int baseLen, allLen, totalLen = 2, baseID;
06199     LPWSTR filter = NULL, baseFilter, all;
06200     LPCWSTR filterStr;
06201 
06202     switch (exportFormat)
06203     {
06204     case CRYPTUI_WIZ_EXPORT_FORMAT_BASE64:
06205         baseID = IDS_EXPORT_FILTER_BASE64_CERT;
06206         filterStr = export_filter_cert;
06207         break;
06208     case CRYPTUI_WIZ_EXPORT_FORMAT_PFX:
06209         baseID = IDS_EXPORT_FILTER_PFX;
06210         filterStr = export_filter_pfx;
06211         break;
06212     case CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7:
06213         baseID = IDS_EXPORT_FILTER_CMS;
06214         filterStr = export_filter_cms;
06215         break;
06216     default:
06217         switch (subjectChoice)
06218         {
06219         case CRYPTUI_WIZ_EXPORT_CRL_CONTEXT:
06220             baseID = IDS_EXPORT_FILTER_CRL;
06221             filterStr = export_filter_crl;
06222             break;
06223         case CRYPTUI_WIZ_EXPORT_CTL_CONTEXT:
06224             baseID = IDS_EXPORT_FILTER_CTL;
06225             filterStr = export_filter_ctl;
06226             break;
06227         case CRYPTUI_WIZ_EXPORT_CERT_STORE:
06228             baseID = IDS_EXPORT_FILTER_SERIALIZED_CERT_STORE;
06229             filterStr = export_filter_sst;
06230             break;
06231         default:
06232             baseID = IDS_EXPORT_FILTER_CERT;
06233             filterStr = export_filter_cert;
06234             break;
06235         }
06236     }
06237     baseLen = LoadStringW(hInstance, baseID, (LPWSTR)&baseFilter, 0);
06238     totalLen += baseLen + strlenW(filterStr) + 2;
06239     allLen = LoadStringW(hInstance, IDS_IMPORT_FILTER_ALL, (LPWSTR)&all, 0);
06240     totalLen += allLen + strlenW(filter_all) + 2;
06241     filter = HeapAlloc(GetProcessHeap(), 0, totalLen * sizeof(WCHAR));
06242     if (filter)
06243     {
06244         LPWSTR ptr;
06245 
06246         ptr = filter;
06247         memcpy(ptr, baseFilter, baseLen * sizeof(WCHAR));
06248         ptr += baseLen;
06249         *ptr++ = 0;
06250         strcpyW(ptr, filterStr);
06251         ptr += strlenW(filterStr) + 1;
06252         memcpy(ptr, all, allLen * sizeof(WCHAR));
06253         ptr += allLen;
06254         *ptr++ = 0;
06255         strcpyW(ptr, filter_all);
06256         ptr += strlenW(filter_all) + 1;
06257         *ptr++ = 0;
06258     }
06259     return filter;
06260 }
06261 
06262 static LRESULT CALLBACK export_file_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
06263  LPARAM lp)
06264 {
06265     LRESULT ret = 0;
06266     struct ExportWizData *data;
06267 
06268     switch (msg)
06269     {
06270     case WM_INITDIALOG:
06271     {
06272         PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp;
06273 
06274         data = (struct ExportWizData *)page->lParam;
06275         SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
06276         if (data->exportInfo.pwszExportFileName)
06277             SendMessageW(GetDlgItem(hwnd, IDC_EXPORT_FILENAME), WM_SETTEXT, 0,
06278              (LPARAM)data->exportInfo.pwszExportFileName);
06279         break;
06280     }
06281     case WM_NOTIFY:
06282     {
06283         NMHDR *hdr = (NMHDR *)lp;
06284 
06285         switch (hdr->code)
06286         {
06287         case PSN_WIZBACK:
06288             data = (struct ExportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
06289             if (data->contextInfo.dwExportFormat !=
06290              CRYPTUI_WIZ_EXPORT_FORMAT_PFX)
06291             {
06292                 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, IDD_EXPORT_FORMAT);
06293                 ret = 1;
06294             }
06295             break;
06296         case PSN_WIZNEXT:
06297         {
06298             HWND fileNameEdit = GetDlgItem(hwnd, IDC_EXPORT_FILENAME);
06299             DWORD len = SendMessageW(fileNameEdit, WM_GETTEXTLENGTH, 0, 0);
06300 
06301             data = (struct ExportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
06302             if (!len)
06303             {
06304                 WCHAR title[MAX_STRING_LEN], error[MAX_STRING_LEN];
06305                 LPCWSTR pTitle;
06306 
06307                 if (data->pwszWizardTitle)
06308                     pTitle = data->pwszWizardTitle;
06309                 else
06310                 {
06311                     LoadStringW(hInstance, IDS_EXPORT_WIZARD, title,
06312                      sizeof(title) / sizeof(title[0]));
06313                     pTitle = title;
06314                 }
06315                 LoadStringW(hInstance, IDS_IMPORT_EMPTY_FILE, error,
06316                  sizeof(error) / sizeof(error[0]));
06317                 MessageBoxW(hwnd, error, pTitle, MB_ICONERROR | MB_OK);
06318                 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, 1);
06319                 ret = 1;
06320             }
06321             else
06322             {
06323                 LPWSTR fileName = HeapAlloc(GetProcessHeap(), 0,
06324                  (len + 1) * sizeof(WCHAR));
06325 
06326                 if (fileName)
06327                 {
06328                     SendMessageW(fileNameEdit, WM_GETTEXT, len + 1,
06329                      (LPARAM)fileName);
06330                     fileName = export_append_extension(data, fileName);
06331                     if (!export_validate_filename(hwnd, data, fileName))
06332                     {
06333                         HeapFree(GetProcessHeap(), 0, fileName);
06334                         SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, 1);
06335                         ret = 1;
06336                     }
06337                     else
06338                         data->fileName = fileName;
06339                 }
06340             }
06341             break;
06342         }
06343         case PSN_SETACTIVE:
06344             PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0,
06345              PSWIZB_BACK | PSWIZB_NEXT);
06346             ret = TRUE;
06347             break;
06348         }
06349         break;
06350     }
06351     case WM_COMMAND:
06352         switch (wp)
06353         {
06354         case IDC_EXPORT_BROWSE_FILE:
06355         {
06356             OPENFILENAMEW ofn;
06357             WCHAR fileBuf[MAX_PATH];
06358 
06359             data = (struct ExportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
06360             memset(&ofn, 0, sizeof(ofn));
06361             ofn.lStructSize = sizeof(ofn);
06362             ofn.hwndOwner = hwnd;
06363             ofn.lpstrFilter = make_export_file_filter(
06364              data->contextInfo.dwExportFormat,
06365              data->exportInfo.dwSubjectChoice);
06366             ofn.lpstrFile = fileBuf;
06367             ofn.nMaxFile = sizeof(fileBuf) / sizeof(fileBuf[0]);
06368             fileBuf[0] = 0;
06369             if (GetSaveFileNameW(&ofn))
06370                 SendMessageW(GetDlgItem(hwnd, IDC_EXPORT_FILENAME), WM_SETTEXT,
06371                  0, (LPARAM)ofn.lpstrFile);
06372             HeapFree(GetProcessHeap(), 0, (LPWSTR)ofn.lpstrFilter);
06373             break;
06374         }
06375         }
06376         break;
06377     }
06378     return ret;
06379 }
06380 
06381 static void show_export_details(HWND lv, const struct ExportWizData *data)
06382 {
06383     WCHAR text[MAX_STRING_LEN];
06384     LVITEMW item;
06385     int contentID;
06386 
06387     item.mask = LVIF_TEXT;
06388     if (data->fileName)
06389     {
06390         item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
06391         item.iSubItem = 0;
06392         LoadStringW(hInstance, IDS_IMPORT_FILE, text,
06393          sizeof(text)/ sizeof(text[0]));
06394         item.pszText = text;
06395         SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
06396         item.iSubItem = 1;
06397         item.pszText = data->fileName;
06398         SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
06399     }
06400 
06401     item.pszText = text;
06402     switch (data->exportInfo.dwSubjectChoice)
06403     {
06404     case CRYPTUI_WIZ_EXPORT_CRL_CONTEXT:
06405     case CRYPTUI_WIZ_EXPORT_CTL_CONTEXT:
06406     case CRYPTUI_WIZ_EXPORT_CERT_STORE:
06407     case CRYPTUI_WIZ_EXPORT_CERT_STORE_CERTIFICATES_ONLY:
06408         /* do nothing */
06409         break;
06410     default:
06411     {
06412         item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
06413         item.iSubItem = 0;
06414         LoadStringW(hInstance, IDS_EXPORT_INCLUDE_CHAIN, text,
06415          sizeof(text) / sizeof(text[0]));
06416         SendMessageW(lv, LVM_INSERTITEMW, item.iItem, (LPARAM)&item);
06417         item.iSubItem = 1;
06418         LoadStringW(hInstance,
06419          data->contextInfo.fExportChain ? IDS_YES : IDS_NO, text,
06420          sizeof(text) / sizeof(text[0]));
06421         SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
06422 
06423         item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
06424         item.iSubItem = 0;
06425         LoadStringW(hInstance, IDS_EXPORT_KEYS, text,
06426          sizeof(text) / sizeof(text[0]));
06427         SendMessageW(lv, LVM_INSERTITEMW, item.iItem, (LPARAM)&item);
06428         item.iSubItem = 1;
06429         LoadStringW(hInstance,
06430          data->contextInfo.fExportPrivateKeys ? IDS_YES : IDS_NO, text,
06431          sizeof(text) / sizeof(text[0]));
06432         SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
06433     }
06434     }
06435 
06436     item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
06437     item.iSubItem = 0;
06438     LoadStringW(hInstance, IDS_EXPORT_FORMAT, text,
06439      sizeof(text)/ sizeof(text[0]));
06440     SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
06441 
06442     item.iSubItem = 1;
06443     switch (data->exportInfo.dwSubjectChoice)
06444     {
06445     case CRYPTUI_WIZ_EXPORT_CRL_CONTEXT:
06446         contentID = IDS_EXPORT_FILTER_CRL;
06447         break;
06448     case CRYPTUI_WIZ_EXPORT_CTL_CONTEXT:
06449         contentID = IDS_EXPORT_FILTER_CTL;
06450         break;
06451     case CRYPTUI_WIZ_EXPORT_CERT_STORE:
06452         contentID = IDS_EXPORT_FILTER_SERIALIZED_CERT_STORE;
06453         break;
06454     default:
06455         switch (data->contextInfo.dwExportFormat)
06456         {
06457         case CRYPTUI_WIZ_EXPORT_FORMAT_BASE64:
06458             contentID = IDS_EXPORT_FILTER_BASE64_CERT;
06459             break;
06460         case CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7:
06461             contentID = IDS_EXPORT_FILTER_CMS;
06462             break;
06463         case CRYPTUI_WIZ_EXPORT_FORMAT_PFX:
06464             contentID = IDS_EXPORT_FILTER_PFX;
06465             break;
06466         default:
06467             contentID = IDS_EXPORT_FILTER_CERT;
06468         }
06469     }
06470     LoadStringW(hInstance, contentID, text, sizeof(text) / sizeof(text[0]));
06471     SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
06472 }
06473 
06474 static inline BOOL save_der(HANDLE file, const BYTE *pb, DWORD cb)
06475 {
06476     DWORD bytesWritten;
06477 
06478     return WriteFile(file, pb, cb, &bytesWritten, NULL);
06479 }
06480 
06481 static BOOL save_base64(HANDLE file, const BYTE *pb, DWORD cb)
06482 {
06483     BOOL ret;
06484     DWORD size = 0;
06485 
06486     if ((ret = CryptBinaryToStringA(pb, cb, CRYPT_STRING_BASE64, NULL, &size)))
06487     {
06488         LPSTR buf = HeapAlloc(GetProcessHeap(), 0, size);
06489 
06490         if (buf)
06491         {
06492             if ((ret = CryptBinaryToStringA(pb, cb, CRYPT_STRING_BASE64, buf,
06493              &size)))
06494                 ret = WriteFile(file, buf, size, &size, NULL);
06495             HeapFree(GetProcessHeap(), 0, buf);
06496         }
06497         else
06498         {
06499             SetLastError(ERROR_OUTOFMEMORY);
06500             ret = FALSE;
06501         }
06502     }
06503     return ret;
06504 }
06505 
06506 static inline BOOL save_store_as_cms(HANDLE file, HCERTSTORE store)
06507 {
06508     return CertSaveStore(store, PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
06509      CERT_STORE_SAVE_AS_PKCS7, CERT_STORE_SAVE_TO_FILE, file, 0);
06510 }
06511 
06512 static BOOL save_cert_as_cms(HANDLE file, PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo,
06513  BOOL includeChain)
06514 {
06515     BOOL ret;
06516     HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
06517      CERT_STORE_CREATE_NEW_FLAG, NULL);
06518 
06519     if (store)
06520     {
06521         if (includeChain)
06522         {
06523             HCERTSTORE addlStore = CertOpenStore(CERT_STORE_PROV_COLLECTION,
06524              0, 0, CERT_STORE_CREATE_NEW_FLAG, NULL);
06525 
06526             if (addlStore)
06527             {
06528                 DWORD i;
06529 
06530                 ret = TRUE;
06531                 for (i = 0; ret && i < pExportInfo->cStores; i++)
06532                     ret = CertAddStoreToCollection(addlStore,
06533                      pExportInfo->rghStores, 0, 0);
06534                 if (ret)
06535                 {
06536                     PCCERT_CHAIN_CONTEXT chain;
06537 
06538                     ret = CertGetCertificateChain(NULL,
06539                      pExportInfo->u.pCertContext, NULL, addlStore, NULL, 0,
06540                      NULL, &chain);
06541                     if (ret)
06542                     {
06543                         DWORD j;
06544 
06545                         for (i = 0; ret && i < chain->cChain; i++)
06546                             for (j = 0; ret && j < chain->rgpChain[i]->cElement;
06547                              j++)
06548                                 ret = CertAddCertificateContextToStore(store,
06549                                  chain->rgpChain[i]->rgpElement[j]->pCertContext,
06550                                  CERT_STORE_ADD_ALWAYS, NULL);
06551                         CertFreeCertificateChain(chain);
06552                     }
06553                     else
06554                     {
06555                         /* No chain could be created, just add the individual
06556                          * cert to the message.
06557                          */
06558                         ret = CertAddCertificateContextToStore(store,
06559                          pExportInfo->u.pCertContext, CERT_STORE_ADD_ALWAYS,
06560                          NULL);
06561                     }
06562                 }
06563                 CertCloseStore(addlStore, 0);
06564             }
06565             else
06566                 ret = FALSE;
06567         }
06568         else
06569             ret = CertAddCertificateContextToStore(store,
06570              pExportInfo->u.pCertContext, CERT_STORE_ADD_ALWAYS, NULL);
06571         if (ret)
06572             ret = save_store_as_cms(file, store);
06573         CertCloseStore(store, 0);
06574     }
06575     else
06576         ret = FALSE;
06577     return ret;
06578 }
06579 
06580 static BOOL save_serialized_store(HANDLE file, HCERTSTORE store)
06581 {
06582     return CertSaveStore(store, PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
06583      CERT_STORE_SAVE_AS_STORE, CERT_STORE_SAVE_TO_FILE, file, 0);
06584 }
06585 
06586 static BOOL save_pfx(HANDLE file, PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo,
06587  PCCRYPTUI_WIZ_EXPORT_CERTCONTEXT_INFO pContextInfo,
06588  PCRYPT_KEY_PROV_INFO keyProvInfo, BOOL deleteKeys)
06589 {
06590     HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, X509_ASN_ENCODING,
06591      0, CERT_STORE_CREATE_NEW_FLAG, NULL);
06592     BOOL ret = FALSE;
06593 
06594     if (store)
06595     {
06596         CRYPT_DATA_BLOB pfxBlob = { 0, NULL };
06597         PCCERT_CONTEXT cert = NULL;
06598         BOOL freeKeyProvInfo = FALSE;
06599 
06600         if (pContextInfo->fExportChain)
06601         {
06602             HCERTCHAINENGINE engine = NULL;
06603 
06604             if (pExportInfo->cStores)
06605             {
06606                 CERT_CHAIN_ENGINE_CONFIG config;
06607 
06608                 memset(&config, 0, sizeof(config));
06609                 config.cbSize = sizeof(config);
06610                 config.cAdditionalStore = pExportInfo->cStores;
06611                 config.rghAdditionalStore = pExportInfo->rghStores;
06612                 ret = CertCreateCertificateChainEngine(&config, &engine);
06613             }
06614             else
06615                 ret = TRUE;
06616             if (ret)
06617             {
06618                 CERT_CHAIN_PARA chainPara;
06619                 PCCERT_CHAIN_CONTEXT chain;
06620 
06621                 memset(&chainPara, 0, sizeof(chainPara));
06622                 chainPara.cbSize = sizeof(chainPara);
06623                 ret = CertGetCertificateChain(engine,
06624                  pExportInfo->u.pCertContext, NULL, NULL, &chainPara, 0, NULL,
06625                  &chain);
06626                 if (ret)
06627                 {
06628                     DWORD i, j;
06629 
06630                     for (i = 0; ret && i < chain->cChain; i++)
06631                         for (j = 0; ret && j < chain->rgpChain[i]->cElement;
06632                          j++)
06633                         {
06634                             if (i == 0 && j == 0)
06635                                 ret = CertAddCertificateContextToStore(store,
06636                                  chain->rgpChain[i]->rgpElement[j]->pCertContext,
06637                                  CERT_STORE_ADD_ALWAYS, &cert);
06638                             else
06639                                 ret = CertAddCertificateContextToStore(store,
06640                                  chain->rgpChain[i]->rgpElement[j]->pCertContext,
06641                                  CERT_STORE_ADD_ALWAYS, NULL);
06642                         }
06643                     CertFreeCertificateChain(chain);
06644                 }
06645             }
06646             if (engine)
06647                 CertFreeCertificateChainEngine(engine);
06648         }
06649         else
06650             ret = CertAddCertificateContextToStore(store,
06651              pExportInfo->u.pCertContext, CERT_STORE_ADD_ALWAYS, &cert);
06652         /* Copy private key info to newly created cert, so it'll get exported
06653          * along with the cert.
06654          */
06655         if (ret && pContextInfo->fExportPrivateKeys)
06656         {
06657             if (keyProvInfo)
06658                 ret = CertSetCertificateContextProperty(cert,
06659                  CERT_KEY_PROV_INFO_PROP_ID, 0, keyProvInfo);
06660             else
06661             {
06662                 if (!(keyProvInfo = export_get_private_key_info(cert)))
06663                     ret = FALSE;
06664                 else
06665                 {
06666                     ret = CertSetCertificateContextProperty(cert,
06667                      CERT_KEY_PROV_INFO_PROP_ID, 0, keyProvInfo);
06668                     freeKeyProvInfo = TRUE;
06669                 }
06670             }
06671         }
06672         if (ret)
06673         {
06674             DWORD exportFlags =
06675              REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY | EXPORT_PRIVATE_KEYS;
06676 
06677             ret = PFXExportCertStore(store, &pfxBlob,
06678              pContextInfo->pwszPassword, exportFlags);
06679             if (ret)
06680             {
06681                 pfxBlob.pbData = HeapAlloc(GetProcessHeap(), 0, pfxBlob.cbData);
06682                 if (pfxBlob.pbData)
06683                 {
06684                     ret = PFXExportCertStore(store, &pfxBlob,
06685                      pContextInfo->pwszPassword, exportFlags);
06686                     if (ret)
06687                     {
06688                         DWORD bytesWritten;
06689 
06690                         ret = WriteFile(file, pfxBlob.pbData, pfxBlob.cbData,
06691                          &bytesWritten, NULL);
06692                     }
06693                 }
06694                 else
06695                 {
06696                     SetLastError(ERROR_OUTOFMEMORY);
06697                     ret = FALSE;
06698                 }
06699             }
06700         }
06701         if (ret && deleteKeys)
06702         {
06703             HCRYPTPROV prov;
06704 
06705             CryptAcquireContextW(&prov, keyProvInfo->pwszContainerName,
06706              keyProvInfo->pwszProvName, keyProvInfo->dwProvType,
06707              CRYPT_DELETEKEYSET);
06708         }
06709         if (freeKeyProvInfo)
06710             HeapFree(GetProcessHeap(), 0, keyProvInfo);
06711         CertFreeCertificateContext(cert);
06712         CertCloseStore(store, 0);
06713     }
06714     return ret;
06715 }
06716 
06717 static BOOL do_export(HANDLE file, PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo,
06718  PCCRYPTUI_WIZ_EXPORT_CERTCONTEXT_INFO pContextInfo,
06719  PCRYPT_KEY_PROV_INFO keyProvInfo, BOOL deleteKeys)
06720 {
06721     BOOL ret;
06722 
06723     if (pContextInfo->dwSize != sizeof(CRYPTUI_WIZ_EXPORT_CERTCONTEXT_INFO))
06724     {
06725         SetLastError(E_INVALIDARG);
06726         return FALSE;
06727     }
06728     switch (pExportInfo->dwSubjectChoice)
06729     {
06730     case CRYPTUI_WIZ_EXPORT_CRL_CONTEXT:
06731         ret = save_der(file,
06732          pExportInfo->u.pCRLContext->pbCrlEncoded,
06733          pExportInfo->u.pCRLContext->cbCrlEncoded);
06734         break;
06735     case CRYPTUI_WIZ_EXPORT_CTL_CONTEXT:
06736         ret = save_der(file,
06737          pExportInfo->u.pCTLContext->pbCtlEncoded,
06738          pExportInfo->u.pCTLContext->cbCtlEncoded);
06739         break;
06740     case CRYPTUI_WIZ_EXPORT_CERT_STORE:
06741         ret = save_serialized_store(file, pExportInfo->u.hCertStore);
06742         break;
06743     case CRYPTUI_WIZ_EXPORT_CERT_STORE_CERTIFICATES_ONLY:
06744         ret = save_store_as_cms(file, pExportInfo->u.hCertStore);
06745         break;
06746     default:
06747         switch (pContextInfo->dwExportFormat)
06748         {
06749         case CRYPTUI_WIZ_EXPORT_FORMAT_DER:
06750             ret = save_der(file, pExportInfo->u.pCertContext->pbCertEncoded,
06751              pExportInfo->u.pCertContext->cbCertEncoded);
06752             break;
06753         case CRYPTUI_WIZ_EXPORT_FORMAT_BASE64:
06754             ret = save_base64(file,
06755              pExportInfo->u.pCertContext->pbCertEncoded,
06756              pExportInfo->u.pCertContext->cbCertEncoded);
06757             break;
06758         case CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7:
06759             ret = save_cert_as_cms(file, pExportInfo,
06760              pContextInfo->fExportChain);
06761             break;
06762         case CRYPTUI_WIZ_EXPORT_FORMAT_PFX:
06763             ret = save_pfx(file, pExportInfo, pContextInfo, keyProvInfo,
06764              deleteKeys);
06765             break;
06766         default:
06767             SetLastError(E_FAIL);
06768             ret = FALSE;
06769         }
06770     }
06771     return ret;
06772 }
06773 
06774 static LRESULT CALLBACK export_finish_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
06775  LPARAM lp)
06776 {
06777     LRESULT ret = 0;
06778     struct ExportWizData *data;
06779 
06780     switch (msg)
06781     {
06782     case WM_INITDIALOG:
06783     {
06784         PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp;
06785         HWND lv = GetDlgItem(hwnd, IDC_EXPORT_SETTINGS);
06786         RECT rc;
06787         LVCOLUMNW column;
06788 
06789         data = (struct ExportWizData *)page->lParam;
06790         SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
06791         SendMessageW(GetDlgItem(hwnd, IDC_EXPORT_TITLE), WM_SETFONT,
06792          (WPARAM)data->titleFont, TRUE);
06793         GetWindowRect(lv, &rc);
06794         column.mask = LVCF_WIDTH;
06795         column.cx = (rc.right - rc.left) / 2 - 2;
06796         SendMessageW(lv, LVM_INSERTCOLUMNW, 0, (LPARAM)&column);
06797         SendMessageW(lv, LVM_INSERTCOLUMNW, 1, (LPARAM)&column);
06798         show_export_details(lv, data);
06799         break;
06800     }
06801     case WM_NOTIFY:
06802     {
06803         NMHDR *hdr = (NMHDR *)lp;
06804 
06805         switch (hdr->code)
06806         {
06807         case PSN_SETACTIVE:
06808         {
06809             HWND lv = GetDlgItem(hwnd, IDC_EXPORT_SETTINGS);
06810 
06811             data = (struct ExportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
06812             SendMessageW(lv, LVM_DELETEALLITEMS, 0, 0);
06813             show_export_details(lv, data);
06814             PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0,
06815              PSWIZB_BACK | PSWIZB_FINISH);
06816             ret = TRUE;
06817             break;
06818         }
06819         case PSN_WIZFINISH:
06820         {
06821             int messageID;
06822             WCHAR title[MAX_STRING_LEN], message[MAX_STRING_LEN];
06823             LPCWSTR pTitle;
06824             DWORD mbFlags;
06825 
06826             data = (struct ExportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
06827             if ((data->success = do_export(data->file, &data->exportInfo,
06828              &data->contextInfo, data->keyProvInfo, data->deleteKeys)))
06829             {
06830                 messageID = IDS_EXPORT_SUCCEEDED;
06831                 mbFlags = MB_OK;
06832             }
06833             else
06834             {
06835                 messageID = IDS_EXPORT_FAILED;
06836                 mbFlags = MB_OK | MB_ICONERROR;
06837             }
06838             if (data->pwszWizardTitle)
06839                 pTitle = data->pwszWizardTitle;
06840             else
06841             {
06842                 LoadStringW(hInstance, IDS_EXPORT_WIZARD, title,
06843                  sizeof(title) / sizeof(title[0]));
06844                 pTitle = title;
06845             }
06846             LoadStringW(hInstance, messageID, message,
06847              sizeof(message) / sizeof(message[0]));
06848             MessageBoxW(hwnd, message, pTitle, mbFlags);
06849             break;
06850         }
06851         }
06852         break;
06853     }
06854     }
06855     return ret;
06856 }
06857 
06858 static BOOL show_export_ui(DWORD dwFlags, HWND hwndParent,
06859  LPCWSTR pwszWizardTitle, PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo, const void *pvoid)
06860 {
06861     PROPSHEETHEADERW hdr;
06862     PROPSHEETPAGEW pages[6];
06863     struct ExportWizData data;
06864     int nPages = 0;
06865     BOOL hasPrivateKey, showFormatPage = TRUE;
06866     INT_PTR l;
06867 
06868     data.dwFlags = dwFlags;
06869     data.pwszWizardTitle = pwszWizardTitle;
06870     memset(&data.exportInfo, 0, sizeof(data.exportInfo));
06871     memcpy(&data.exportInfo, pExportInfo,
06872      min(sizeof(data.exportInfo), pExportInfo->dwSize));
06873     if (pExportInfo->dwSize > sizeof(data.exportInfo))
06874         data.exportInfo.dwSize = sizeof(data.exportInfo);
06875     data.contextInfo.dwSize = sizeof(data.contextInfo);
06876     data.contextInfo.dwExportFormat = CRYPTUI_WIZ_EXPORT_FORMAT_DER;
06877     data.contextInfo.fExportChain = FALSE;
06878     data.contextInfo.fStrongEncryption = FALSE;
06879     data.contextInfo.fExportPrivateKeys = FALSE;
06880     data.contextInfo.pwszPassword = NULL;
06881     data.freePassword = FALSE;
06882     if (pExportInfo->dwSubjectChoice == CRYPTUI_WIZ_EXPORT_CERT_CONTEXT &&
06883      pvoid)
06884         memcpy(&data.contextInfo, pvoid,
06885          min(((PCCRYPTUI_WIZ_EXPORT_CERTCONTEXT_INFO)pvoid)->dwSize,
06886          sizeof(data.contextInfo)));
06887     data.keyProvInfo = NULL;
06888     data.deleteKeys = FALSE;
06889     data.fileName = NULL;
06890     data.file = INVALID_HANDLE_VALUE;
06891     data.success = FALSE;
06892 
06893     memset(pages, 0, sizeof(pages));
06894 
06895     pages[nPages].dwSize = sizeof(pages[0]);
06896     pages[nPages].hInstance = hInstance;
06897     pages[nPages].u.pszTemplate = MAKEINTRESOURCEW(IDD_EXPORT_WELCOME);
06898     pages[nPages].pfnDlgProc = export_welcome_dlg_proc;
06899     pages[nPages].dwFlags = PSP_HIDEHEADER;
06900     pages[nPages].lParam = (LPARAM)&data;
06901     nPages++;
06902 
06903     hasPrivateKey = export_info_has_private_key(pExportInfo);
06904     switch (pExportInfo->dwSubjectChoice)
06905     {
06906     case CRYPTUI_WIZ_EXPORT_CRL_CONTEXT:
06907     case CRYPTUI_WIZ_EXPORT_CTL_CONTEXT:
06908         showFormatPage = FALSE;
06909         data.contextInfo.dwExportFormat = CRYPTUI_WIZ_EXPORT_FORMAT_DER;
06910         break;
06911     case CRYPTUI_WIZ_EXPORT_CERT_STORE:
06912         showFormatPage = FALSE;
06913         data.contextInfo.dwExportFormat =
06914          CRYPTUI_WIZ_EXPORT_FORMAT_SERIALIZED_CERT_STORE;
06915         break;
06916     case CRYPTUI_WIZ_EXPORT_CERT_STORE_CERTIFICATES_ONLY:
06917         showFormatPage = FALSE;
06918         data.contextInfo.dwExportFormat = CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7;
06919         break;
06920     }
06921 
06922     if (hasPrivateKey && showFormatPage)
06923     {
06924         pages[nPages].dwSize = sizeof(pages[0]);
06925         pages[nPages].hInstance = hInstance;
06926         pages[nPages].u.pszTemplate = MAKEINTRESOURCEW(IDD_EXPORT_PRIVATE_KEY);
06927         pages[nPages].pfnDlgProc = export_private_key_dlg_proc;
06928         pages[nPages].dwFlags = PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
06929         pages[nPages].pszHeaderTitle =
06930          MAKEINTRESOURCEW(IDS_EXPORT_PRIVATE_KEY_TITLE);
06931         pages[nPages].pszHeaderSubTitle =
06932          MAKEINTRESOURCEW(IDS_EXPORT_PRIVATE_KEY_SUBTITLE);
06933         pages[nPages].lParam = (LPARAM)&data;
06934         nPages++;
06935     }
06936     if (showFormatPage)
06937     {
06938         pages[nPages].dwSize = sizeof(pages[0]);
06939         pages[nPages].hInstance = hInstance;
06940         pages[nPages].u.pszTemplate = MAKEINTRESOURCEW(IDD_EXPORT_FORMAT);
06941         pages[nPages].pfnDlgProc = export_format_dlg_proc;
06942         pages[nPages].dwFlags = PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
06943         pages[nPages].pszHeaderTitle =
06944          MAKEINTRESOURCEW(IDS_EXPORT_FORMAT_TITLE);
06945         pages[nPages].pszHeaderSubTitle =
06946          MAKEINTRESOURCEW(IDS_EXPORT_FORMAT_SUBTITLE);
06947         pages[nPages].lParam = (LPARAM)&data;
06948         nPages++;
06949     }
06950     if (hasPrivateKey && showFormatPage)
06951     {
06952         pages[nPages].dwSize = sizeof(pages[0]);
06953         pages[nPages].hInstance = hInstance;
06954         pages[nPages].u.pszTemplate = MAKEINTRESOURCEW(IDD_EXPORT_PASSWORD);
06955         pages[nPages].pfnDlgProc = export_password_dlg_proc;
06956         pages[nPages].dwFlags = PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
06957         pages[nPages].pszHeaderTitle =
06958          MAKEINTRESOURCEW(IDS_EXPORT_PASSWORD_TITLE);
06959         pages[nPages].pszHeaderSubTitle =
06960          MAKEINTRESOURCEW(IDS_EXPORT_PASSWORD_SUBTITLE);
06961         pages[nPages].lParam = (LPARAM)&data;
06962         nPages++;
06963     }
06964 
06965     pages[nPages].dwSize = sizeof(pages[0]);
06966     pages[nPages].hInstance = hInstance;
06967     pages[nPages].u.pszTemplate = MAKEINTRESOURCEW(IDD_EXPORT_FILE);
06968     pages[nPages].pfnDlgProc = export_file_dlg_proc;
06969     pages[nPages].dwFlags = PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
06970     pages[nPages].pszHeaderTitle = MAKEINTRESOURCEW(IDS_EXPORT_FILE_TITLE);
06971     pages[nPages].pszHeaderSubTitle =
06972      MAKEINTRESOURCEW(IDS_EXPORT_FILE_SUBTITLE);
06973     pages[nPages].lParam = (LPARAM)&data;
06974     nPages++;
06975 
06976     pages[nPages].dwSize = sizeof(pages[0]);
06977     pages[nPages].hInstance = hInstance;
06978     pages[nPages].u.pszTemplate = MAKEINTRESOURCEW(IDD_EXPORT_FINISH);
06979     pages[nPages].pfnDlgProc = export_finish_dlg_proc;
06980     pages[nPages].dwFlags = PSP_HIDEHEADER;
06981     pages[nPages].lParam = (LPARAM)&data;
06982     nPages++;
06983 
06984     memset(&hdr, 0, sizeof(hdr));
06985     hdr.dwSize = sizeof(hdr);
06986     hdr.hwndParent = hwndParent;
06987     hdr.dwFlags = PSH_PROPSHEETPAGE | PSH_WIZARD97_NEW | PSH_HEADER |
06988      PSH_WATERMARK;
06989     hdr.hInstance = hInstance;
06990     if (pwszWizardTitle)
06991         hdr.pszCaption = pwszWizardTitle;
06992     else
06993         hdr.pszCaption = MAKEINTRESOURCEW(IDS_EXPORT_WIZARD);
06994     hdr.u3.ppsp = pages;
06995     hdr.nPages = nPages;
06996     hdr.u4.pszbmWatermark = MAKEINTRESOURCEW(IDB_CERT_WATERMARK);
06997     hdr.u5.pszbmHeader = MAKEINTRESOURCEW(IDB_CERT_HEADER);
06998     l = PropertySheetW(&hdr);
06999     DeleteObject(data.titleFont);
07000     if (data.freePassword)
07001         HeapFree(GetProcessHeap(), 0,
07002          (LPWSTR)data.contextInfo.pwszPassword);
07003     HeapFree(GetProcessHeap(), 0, data.keyProvInfo);
07004     CloseHandle(data.file);
07005     HeapFree(GetProcessHeap(), 0, data.fileName);
07006     if (l == 0)
07007     {
07008         SetLastError(ERROR_CANCELLED);
07009         return FALSE;
07010     }
07011     else
07012         return data.success;
07013 }
07014 
07015 BOOL WINAPI CryptUIWizExport(DWORD dwFlags, HWND hwndParent,
07016  LPCWSTR pwszWizardTitle, PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo, void *pvoid)
07017 {
07018     BOOL ret;
07019 
07020     TRACE("(%08x, %p, %s, %p, %p)\n", dwFlags, hwndParent,
07021      debugstr_w(pwszWizardTitle), pExportInfo, pvoid);
07022 
07023     if (!(dwFlags & CRYPTUI_WIZ_NO_UI))
07024         ret = show_export_ui(dwFlags, hwndParent, pwszWizardTitle, pExportInfo,
07025          pvoid);
07026     else
07027     {
07028         HANDLE file = CreateFileW(pExportInfo->pwszExportFileName,
07029          GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
07030          CREATE_ALWAYS, 0, NULL);
07031 
07032         if (file != INVALID_HANDLE_VALUE)
07033         {
07034             ret = do_export(file, pExportInfo, pvoid, NULL, FALSE);
07035             CloseHandle(file);
07036         }
07037         else
07038             ret = FALSE;
07039     }
07040     return ret;
07041 }
07042 
07043 BOOL WINAPI CryptUIDlgViewSignerInfoA(CRYPTUI_VIEWSIGNERINFO_STRUCTA *pcvsi)
07044 {
07045     FIXME("%p: stub\n", pcvsi);
07046     return FALSE;
07047 }
07048 
07049 PCCERT_CONTEXT WINAPI CryptUIDlgSelectCertificateW(PCCRYPTUI_SELECTCERTIFICATE_STRUCTW pcsc)
07050 {
07051     FIXME("%p: stub\n", pcsc);
07052     return NULL;
07053 }
07054 
07055 PCCERT_CONTEXT WINAPI CryptUIDlgSelectCertificateA(PCCRYPTUI_SELECTCERTIFICATE_STRUCTA pcsc)
07056 {
07057     FIXME("%p: stub\n", pcsc);
07058     return NULL;
07059 }

Generated on Sun May 27 2012 04:16:41 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.