Exemple #1
0
KHMEXP khm_int32   KHMAPI
kmm_enable_plugin(kmm_plugin p, khm_boolean enable) {
    kmm_plugin_i * pi;
    khm_int32 rv = KHM_ERROR_NOT_FOUND; /* default to error */
    khm_handle csp_plugin = NULL;

    EnterCriticalSection(&cs_kmm);
    if (!kmm_is_plugin(p)) {
        rv = KHM_ERROR_INVALID_PARAM;
        goto _cleanup;
    }

    pi = kmm_plugin_from_handle(p);

    if (KHM_FAILED(rv = kmm_get_plugin_config(pi->p.name, 0, &csp_plugin))) {
        goto _cleanup;
    }

    if (KHM_FAILED(rv = khc_write_int32(csp_plugin, L"Disabled", !enable))) {
        goto _cleanup;
    }

    rv = KHM_ERROR_SUCCESS;

 _cleanup:
    LeaveCriticalSection(&cs_kmm);

    if (csp_plugin)
        khc_close_space(csp_plugin);

    return rv;
}
Exemple #2
0
/* Identity Selector control factory

   Runs in UI thread */
khm_int32 KHMAPI
idsel_factory(HWND hwnd_parent, khui_identity_selector * u) {

    if (hwnd_parent) {
        HWND hw_dlg;
        wchar_t display_name[KHUI_MAXCCH_NAME] = L"";
        khm_handle csp_p = NULL;
        khm_int32 allow_create = 0;

        if (KHM_FAILED(kmm_get_plugin_config(IDPROV_NAMEW, 0, &csp_p)) ||
            KHM_FAILED(khc_read_int32(csp_p, L"AllowMultipleKeystores", &allow_create)) ||
            allow_create == 0) {
            if (csp_p)
                khc_close_space(csp_p);
            return KHM_ERROR_INVALID_OPERATION;
        }

        if (csp_p) {
            khc_close_space(csp_p);
            csp_p = NULL;
        }

        hw_dlg = CreateDialog(hResModule, MAKEINTRESOURCE(IDD_IDSPEC),
                              hwnd_parent, idspec_dlg_proc);

        assert(hw_dlg);

        u->hwnd_selector = hw_dlg;

        LoadString(hResModule, IDS_ID_INSTANCE, display_name, ARRAYLENGTH(display_name));
        u->display_name = PWCSDUP(display_name);

        u->icon = LoadImage(hResModule, MAKEINTRESOURCE(IDI_IDENTITY),
                            IMAGE_ICON, 0, 0,
                            LR_DEFAULTSIZE | LR_DEFAULTCOLOR);

        return (hw_dlg ? KHM_ERROR_SUCCESS : KHM_ERROR_UNKNOWN);

    } else {

        if (u->display_name) {
            PFREE(u->display_name);
            u->display_name = NULL;
        }

        if (u->icon) {
            DestroyIcon(u->icon);
            u->icon = NULL;
        }

        return KHM_ERROR_SUCCESS;
    }
}
Exemple #3
0
KHMEXP khm_int32   KHMAPI
kmm_get_plugin_info_i(kmm_plugin p, kmm_plugin_info * info) {
    khm_int32 rv = KHM_ERROR_SUCCESS;
    kmm_plugin_i * pi;
    khm_handle csp_plugin;

    if (!info)
        return KHM_ERROR_INVALID_PARAM;

    EnterCriticalSection(&cs_kmm);
    if (!kmm_is_plugin(p)) {
        rv = KHM_ERROR_INVALID_PARAM;
        goto _cleanup;
    }

    pi = kmm_plugin_from_handle(p);

    ZeroMemory(info, sizeof(*info));

    info->reg = pi->p;
    info->reg.msg_proc = NULL;

    if (KHM_FAILED(kmm_get_plugin_config(pi->p.name, KHM_PERM_READ,
                                         &csp_plugin))) {
        info->failure_count = 0;
        *((khm_int64 *)&info->failure_time) = 0;
        info->failure_reason = 0;
    } else {
        if (KHM_FAILED(khc_read_int32(csp_plugin, L"FailureCount",
                                      &info->failure_count)))
            info->failure_count = 0;
        if (KHM_FAILED(khc_read_int64(csp_plugin, L"FailureTime",
                                      (khm_int64 *) &info->failure_time)))
            *((khm_int64 *) &info->failure_time) = 0;
        if (KHM_FAILED(khc_read_int32(csp_plugin, L"FailureReason",
                                      &info->failure_reason)))
            info->failure_reason = 0;

        khc_close_space(csp_plugin);
    }

    info->state = pi->state;

    kmm_hold_plugin(p);
    info->h_plugin = p;

    info->flags = (pi->flags & KMM_PLUGIN_FLAG_DISABLED);

 _cleanup:
    LeaveCriticalSection(&cs_kmm);

    return rv;
}
Exemple #4
0
KHMEXP khm_int32   KHMAPI
kmm_unregister_plugin(wchar_t * plugin, khm_int32 config_flags)
{
    khm_handle csp_plugin = NULL;
    khm_int32 rv = KHM_ERROR_SUCCESS;

    rv = kmm_get_plugin_config(plugin, config_flags, &csp_plugin);

    if (KHM_FAILED(rv))
        goto _cleanup;

    rv = khc_remove_space(csp_plugin);

 _cleanup:

    if (csp_plugin)
        khc_close_space(csp_plugin);

    return rv;
}
Exemple #5
0
/* process KMSG_SYSTEM messages */
khm_int32 KHMAPI
afs_msg_system(khm_int32 msg_subtype,
               khm_ui_4 uparam,
               void * vparam)
{
    khm_int32 rv = KHM_ERROR_UNKNOWN;

    switch(msg_subtype) {
    case KMSG_SYSTEM_INIT:

        /* If we are building against an older SDK, we should try to
           load newer APIs if it's available at run-time. */
#if KH_VERSION_API < 7
        do {
            khm_version libver;
            khm_ui_4 apiver;

            khm_get_lib_version(&libver, &apiver);

            if (apiver < 7)
                break;

            hm_netidmgr = LoadLibrary(NIMDLLNAME);

            if (hm_netidmgr == NULL)
                break;

            pkhui_action_lock = (void (KHMAPI *)(void))
                GetProcAddress(hm_netidmgr, API_khui_action_lock);
            pkhui_action_unlock = (void (KHMAPI *)(void))
                GetProcAddress(hm_netidmgr, API_khui_action_unlock);
            pkhui_refresh_actions = (void (KHMAPI *)(void))
                GetProcAddress(hm_netidmgr, API_khui_refresh_actions);
            pkhui_request_UI_callback = (khm_int32 (KHMAPI *)(khm_ui_callback, void *))
                GetProcAddress(hm_netidmgr, API_khui_request_UI_callback);

        } while (FALSE);
#endif

        /* Add the icon now.  On NIM v2.x, doing so after tokens were
           reported may result in a deadlock as we try to switch to
           the UI thread and the UI thread is blocked on a resource
           request to this plug-in. */
        afs_icon_set_state(AFSICON_SERVICE_STOPPED, NULL);

        /* Perform critical registrations and data structure
           initalization */
        {
            kcdb_credtype ct;
            wchar_t buf[KCDB_MAXCCH_LONG_DESC];
            size_t cbsize;
            kcdb_attrib att;
            khm_handle csp_afscred = NULL;
            khm_int32 disable_afscreds = FALSE;

            ZeroMemory(&ct, sizeof(ct));
            /* first of all, register the AFS token credential type */
            ct.id = KCDB_CREDTYPE_AUTO;
            ct.name = AFS_CREDTYPE_NAME;

            if(LoadString(hResModule,
                          IDS_AFS_SHORT_DESC,
                          buf,
                          ARRAYLENGTH(buf)) != 0) {
                StringCbLength(buf, sizeof(buf), &cbsize);
                cbsize += sizeof(wchar_t);
                ct.short_desc = PMALLOC(cbsize);
                StringCbCopy(ct.short_desc, cbsize, buf);
            } else
                ct.short_desc = NULL;

            if(LoadString(hResModule,
                          IDS_AFS_LONG_DESC,
                          buf,
                          ARRAYLENGTH(buf)) != 0) {
                StringCbLength(buf, sizeof(buf), &cbsize);
                cbsize += sizeof(wchar_t);
                ct.long_desc = PMALLOC(cbsize);
                StringCbCopy(ct.long_desc, cbsize, buf);
            } else
                ct.long_desc = NULL;

            ct.icon = LoadImage(hResModule,
                                MAKEINTRESOURCE(IDI_AFSTOKEN),
                                IMAGE_ICON,
                                0, 0, LR_DEFAULTSIZE);

            kmq_create_subscription(afs_plugin_cb, &afs_sub);
            ct.sub = afs_sub;

            kcdb_credtype_register(&ct, &afs_credtype_id);

            /* register the attribute types */
            {
                kcdb_type type;

                ZeroMemory(&type, sizeof(type));
                type.comp = afs_type_principal_comp;
                type.dup = afs_type_principal_dup;
                type.isValid = afs_type_principal_isValid;
                type.toString = afs_type_principal_toString;
                type.name = AFS_TYPENAME_PRINCIPAL;
                type.id = KCDB_TYPE_INVALID;
                type.cb_max = sizeof(struct ktc_principal);
                type.cb_min = sizeof(struct ktc_principal);
                type.flags = KCDB_TYPE_FLAG_CB_FIXED;

                if(KHM_FAILED(kcdb_type_register(&type,
                                                 &afs_type_principal)))
                    goto _exit_init;
            }

            {
                kcdb_type type;
                kcdb_type *ti32 = NULL;

                kcdb_type_get_info(KCDB_TYPE_INT32, &ti32);

                ZeroMemory(&type, sizeof(type));
                type.comp = ti32->comp;
                type.dup = ti32->dup;
                type.isValid = ti32->isValid;
                type.toString = afs_type_method_toString;
                type.name = AFS_TYPENAME_METHOD;
                type.id = KCDB_TYPE_INVALID;
                type.cb_max = sizeof(khm_int32);
                type.cb_min = sizeof(khm_int32);
                type.flags = KCDB_TYPE_FLAG_CB_FIXED;

                if(KHM_FAILED(kcdb_type_register(&type,
                                                 &afs_type_method))) {
                    kcdb_type_release_info(ti32);
                    goto _exit_init;
                }

                kcdb_type_release_info(ti32);
            }

            /* now register the attributes */
            {
                wchar_t short_desc[KCDB_MAXCCH_SHORT_DESC];

                ZeroMemory(&att, sizeof(att));

                att.type = KCDB_TYPE_STRING;
                att.name = AFS_ATTRNAME_CELL;
                LoadString(hResModule,
                           IDS_ATTR_CELL_SHORT_DESC,
                           short_desc,
                           ARRAYLENGTH(short_desc));
                att.short_desc = short_desc;
                att.long_desc = NULL;
                att.id = KCDB_ATTR_INVALID;
                att.flags = KCDB_ATTR_FLAG_TRANSIENT;

                if(KHM_FAILED(rv = kcdb_attrib_register(&att,
                                                        &afs_attr_cell)))
                    goto _exit_init;
            }

            {
                wchar_t short_desc[KCDB_MAXCCH_SHORT_DESC];

                ZeroMemory(&att, sizeof(att));

                att.type = KCDB_TYPE_STRING;
                att.name = AFS_ATTRNAME_REALM;
                LoadString(hResModule,
                           IDS_ATTR_REALM_SHORT_DESC,
                           short_desc,
                           ARRAYLENGTH(short_desc));
                att.short_desc = short_desc;
                att.long_desc = NULL;
                att.id = KCDB_ATTR_INVALID;
                att.flags = KCDB_ATTR_FLAG_TRANSIENT;

                if(KHM_FAILED(rv = kcdb_attrib_register(&att,
                                                        &afs_attr_realm)))
                    goto _exit_init;
            }

            {
                wchar_t short_desc[KCDB_MAXCCH_SHORT_DESC];

                ZeroMemory(&att, sizeof(att));

                att.type = afs_type_method;
                att.name = AFS_ATTRNAME_METHOD;
                LoadString(hResModule,
                           IDS_ATTR_METHOD_SHORT_DESC,
                           short_desc,
                           ARRAYLENGTH(short_desc));
                att.short_desc = short_desc;
                att.long_desc = NULL;
                att.id = KCDB_ATTR_INVALID;
                att.flags = KCDB_ATTR_FLAG_TRANSIENT;

                if(KHM_FAILED(rv = kcdb_attrib_register(&att,
                                                        &afs_attr_method)))
                    goto _exit_init;
            }

            {
                wchar_t short_desc[KCDB_MAXCCH_SHORT_DESC];

                ZeroMemory(&att, sizeof(att));

                att.type = afs_type_principal;
                att.name = AFS_ATTRNAME_CLIENT_PRINC;
                LoadString(hResModule,
                           IDS_ATTR_CLIENT_PRINC_SHORT_DESC,
                           short_desc,
                           ARRAYLENGTH(short_desc));
                att.short_desc = short_desc;
                att.long_desc = NULL;
                att.id = KCDB_ATTR_INVALID;
                att.flags = KCDB_ATTR_FLAG_TRANSIENT;

                if(KHM_FAILED(rv = kcdb_attrib_register(&att, &afs_attr_client_princ)))
                    goto _exit_init;
            }

            {
                wchar_t short_desc[KCDB_MAXCCH_SHORT_DESC];

                ZeroMemory(&att, sizeof(att));

                att.type = afs_type_principal;
                att.name = AFS_ATTRNAME_SERVER_PRINC;
                LoadString(hResModule,
                           IDS_ATTR_SERVER_PRINC_SHORT_DESC,
                           short_desc, ARRAYLENGTH(short_desc));
                att.short_desc = short_desc;
                att.long_desc = NULL;
                att.id = KCDB_ATTR_INVALID;
                att.flags = KCDB_ATTR_FLAG_TRANSIENT;

                if(KHM_FAILED(rv = kcdb_attrib_register(&att, &afs_attr_server_princ)))
                    goto _exit_init;
            }

            /* afs_credset is our stock credentials set that we
               use for all our credset needs (instead of creating
               a new one every time) */

            if(KHM_FAILED(rv = kcdb_credset_create(&afs_credset)))
                goto _exit_init;

            if(KHM_FAILED(rv = kcdb_credtype_get_id(KRB5_CREDTYPE_NAME,
                                                    &krb5_credtype_id)))
                goto _exit_init;

            /* register the configuration nodes */
            {
                khui_config_node node_ident;
                khui_config_node_reg reg;
                wchar_t wshort_desc[KHUI_MAXCCH_SHORT_DESC];
                wchar_t wlong_desc[KHUI_MAXCCH_LONG_DESC];

                if (KHM_FAILED(rv = khui_cfg_open(NULL,
                                                  L"KhmIdentities",
                                                  &node_ident)))
                    goto _exit_init;

                ZeroMemory(&reg, sizeof(reg));
                reg.name = AFS_CONFIG_NODE_MAIN;
                reg.short_desc = wshort_desc;
                reg.long_desc = wlong_desc;
                reg.h_module = hResModule;
                reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_AFS);
                reg.dlg_proc = afs_cfg_main_proc;
                reg.flags = 0;
                LoadString(hResModule, IDS_CFG_MAIN_LONG,
                           wlong_desc, ARRAYLENGTH(wlong_desc));
                LoadString(hResModule, IDS_CFG_MAIN_SHORT,
                           wshort_desc, ARRAYLENGTH(wshort_desc));

                khui_cfg_register(NULL, &reg);

                ZeroMemory(&reg, sizeof(reg));
                reg.name = AFS_CONFIG_NODE_IDS;
                reg.short_desc = wshort_desc;
                reg.long_desc = wshort_desc;
                reg.h_module = hResModule;
                reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_IDS_TAB);
                reg.dlg_proc = afs_cfg_ids_proc;
                reg.flags = KHUI_CNFLAG_SUBPANEL;
                LoadString(hResModule, IDS_CFG_IDS_TAB,
                           wshort_desc, ARRAYLENGTH(wshort_desc));

                khui_cfg_register(node_ident, &reg);

                ZeroMemory(&reg, sizeof(reg));
                reg.name = AFS_CONFIG_NODE_ID;
                reg.short_desc = wshort_desc;
                reg.long_desc = wshort_desc;
                reg.h_module = hResModule;
                reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_ID_TAB);
                reg.dlg_proc = afs_cfg_id_proc;
                reg.flags = KHUI_CNFLAG_SUBPANEL | KHUI_CNFLAG_PLURAL;
                LoadString(hResModule, IDS_CFG_ID_TAB,
                           wshort_desc, ARRAYLENGTH(wshort_desc));

                khui_cfg_register(node_ident, &reg);
            }

            /* and register the AFS message type */
            rv = kmq_register_type(AFS_MSG_TYPENAME, &afs_msg_type_id);

            if (KHM_SUCCEEDED(rv))
                kmq_subscribe(afs_msg_type_id, afs_plugin_cb);

            /* if the configuration is set to disable afscreds.exe,
               then we look for the shortcut and remove it if
               found. */
            if (KHM_SUCCEEDED(kmm_get_plugin_config(AFS_PLUGIN_NAME,
                                                    0,
                                                    &csp_afscred))) {
                wchar_t wpath[MAX_PATH];

                khc_read_int32(csp_afscred, L"Disableafscreds",
                               &disable_afscreds);

                if (disable_afscreds &&
                    afs_cfg_get_afscreds_shortcut(wpath)) {

                    DeleteFile(wpath);

                }

                khc_close_space(csp_afscred);
            }

            /* try to register the "AFS Help" menu item, if
               possible */
            {
                khm_handle h_sub = NULL;
                wchar_t short_desc[KHUI_MAXCCH_SHORT_DESC];
                wchar_t long_desc[KHUI_MAXCCH_LONG_DESC];

#if KH_VERSION_API < 7
                if (pkhui_action_lock == NULL ||
                    pkhui_action_unlock == NULL ||
                    pkhui_refresh_actions == NULL ||
                    pkhui_request_UI_callback == NULL)

                    goto no_custom_help;
#endif

                kmq_create_subscription(afs_plugin_cb, &h_sub);

                LoadString(hResModule, IDS_ACTION_AFS_HELP,
                           short_desc, ARRAYLENGTH(short_desc));
                LoadString(hResModule, IDS_ACTION_AFS_HELP_TT,
                           long_desc, ARRAYLENGTH(long_desc));

                action_id_afs_help = khui_action_create(NULL,
                                                        short_desc,
                                                        long_desc,
                                                        NULL,
                                                        KHUI_ACTIONTYPE_TRIGGER,
                                                        h_sub);

                if (action_id_afs_help != 0) {
                    khm_size s;
                    khm_size i;
                    khui_menu_def * help_menu;
                    khm_boolean refresh = FALSE;

                    khui_action_lock();

                    help_menu = khui_find_menu(KHUI_MENU_HELP);
                    if (help_menu) {
                        s = khui_menu_get_size(help_menu);

                        for (i=0; i < s; i++) {
                            khui_action_ref * aref;

                            aref = khui_menu_get_action(help_menu, i);

                            if (aref && !(aref->flags & KHUI_ACTIONREF_PACTION) &&
                                aref->action == KHUI_ACTION_HELP_INDEX) {

                                khui_menu_insert_action(help_menu,
                                                        i + 1,
                                                        action_id_afs_help,
                                                        0);
                                refresh = TRUE;
                                break;
                            }
                        }
                    }

                    khui_action_unlock();

                    if (refresh)
                        khui_refresh_actions();
                }

#if KH_VERSION_API < 7
            no_custom_help:
                ;
#endif
            }

        _exit_init:
            if(ct.short_desc)
                PFREE(ct.short_desc);
            if(ct.long_desc)
                PFREE(ct.long_desc);
        }
        /* now that the critical stuff is done, we move on to the
           non-critical stuff */
        if(KHM_SUCCEEDED(rv)) {
            initialized = TRUE;

            /* obtain existing tokens */
            afs_list_tokens();
        }

        /* define this so that if there are no TGT's, we don't
           deadlock trying to open a new creds dialog from within the
           new creds dialog. */
        SetEnvironmentVariable(L"KERBEROSLOGIN_NEVER_PROMPT", L"1");

        break;
        /* end of KMSG_SYSTEM_INIT */

    case KMSG_SYSTEM_EXIT:

        afs_remove_icon();

        /* Try to remove the AFS plug-in action from Help menu if it
           was successfully registered.  Also, delete the action. */
        if (action_id_afs_help != 0) {

            khui_menu_def * help_menu;
            khm_boolean menu_changed = FALSE;

            khui_action_lock();

            help_menu = khui_find_menu(KHUI_MENU_HELP);
            if (help_menu) {
                khm_size s;
                khm_size i;

                s = khui_menu_get_size(help_menu);
                for (i=0; i < s; i++) {
                    khui_action_ref * aref = khui_menu_get_action(help_menu, i);

                    if (aref && !(aref->flags & KHUI_ACTIONREF_PACTION) &&
                        aref->action == action_id_afs_help) {

                        khui_menu_remove_action(help_menu, i);
                        menu_changed = TRUE;
                        break;
                    }
                }
            }

            khui_action_delete(action_id_afs_help);

            khui_action_unlock();

            if (menu_changed)
                khui_refresh_actions();

            action_id_afs_help = 0;
        }

        if (afs_msg_type_id != -1) {
            kmq_unsubscribe(afs_msg_type_id, afs_plugin_cb);
            kmq_unregister_type(afs_msg_type_id);
        }
        if(afs_credtype_id >= 0) {
            kcdb_credtype_unregister(afs_credtype_id);
        }
#if 0
        if(afs_attr_client >= 0) {
            kcdb_attrib_unregister(afs_attr_client);
        }
#endif
        if(afs_attr_cell >= 0) {
            kcdb_attrib_unregister(afs_attr_cell);
        }
        if(afs_attr_realm >= 0) {
            kcdb_attrib_unregister(afs_attr_realm);
        }
        if(afs_attr_method >= 0) {
            kcdb_attrib_unregister(afs_attr_method);
        }
        if(afs_attr_client_princ >= 0) {
            kcdb_attrib_unregister(afs_attr_client_princ);
        }
        if(afs_attr_server_princ >= 0) {
            kcdb_attrib_unregister(afs_attr_server_princ);
        }
        if(afs_type_principal >= 0) {
            kcdb_type_unregister(afs_type_principal);
        }
        if(afs_type_method >= 0) {
            kcdb_type_unregister(afs_type_method);
        }
        initialized = FALSE;
        if(afs_credset)
            kcdb_credset_delete(afs_credset);

        /* afs_sub doesn't need to be deleted.  That is taken care
           of when unregistering the afs cred type */
        afs_sub = NULL;

#if KH_VERSION_API < 7
        if (hm_netidmgr)
            FreeLibrary(hm_netidmgr);

        pkhui_action_lock = NULL;
        pkhui_action_unlock = NULL;
        pkhui_refresh_actions = NULL;
        pkhui_request_UI_callback = NULL;
#endif

        rv = KHM_ERROR_SUCCESS;
        break;
        /* end of KMSG_SYSTEM_EXIT */
    }
    return rv;
}
Exemple #6
0
KHMEXP khm_int32   KHMAPI
kmm_register_plugin(kmm_plugin_reg * plugin, khm_int32 config_flags)
{
    khm_int32 rv = KHM_ERROR_SUCCESS;
    khm_handle csp_plugin = NULL;
    khm_handle csp_module = NULL;
    size_t cch;

    /* avoid accidently creating the module key if it doesn't exist */
    config_flags &= ~KHM_FLAG_CREATE;

    if((plugin == NULL) ||
       (plugin->dependencies &&
        KHM_FAILED(multi_string_length_cch(plugin->dependencies,
                                           KMM_MAXCCH_DEPS, &cch))) ||
       FAILED(StringCchLength(plugin->module, KMM_MAXCCH_NAME, &cch)) ||
       (plugin->description &&
        FAILED(StringCchLength(plugin->description,
                               KMM_MAXCCH_DESC, &cch))) ||
       FAILED(StringCchLength(plugin->name, KMM_MAXCCH_NAME, &cch)))
    {
        return KHM_ERROR_INVALID_PARAM;
    }

    /* note that we are retaining the length of the plugin name in
       chars in cch */
    cch ++;

#define CKRV if(KHM_FAILED(rv)) goto _exit

    rv = kmm_get_plugin_config(plugin->name,
                               config_flags | KHM_FLAG_CREATE, &csp_plugin);
    CKRV;

    /* should fail if the module key doesn't exist */
    rv = kmm_get_module_config(plugin->module, config_flags, &csp_module);
    CKRV;

    /*TODO: Make sure that the module registration is in the same
      config store as the one in which the plugin is going to be
      registered */

    rv = khc_write_string(csp_plugin, L"Module", plugin->module);
    CKRV;
    if(plugin->description) {
        rv = khc_write_string(csp_plugin, L"Description", plugin->description);
        CKRV;
    }

    if(plugin->dependencies) {
        rv = khc_write_multi_string(csp_plugin, L"Dependencies",
                                    plugin->dependencies);
        CKRV;
    }

    rv = khc_write_int32(csp_plugin, L"Type", plugin->type);
    CKRV;
    rv = khc_write_int32(csp_plugin, L"Disabled",
                         !!(plugin->flags & KMM_PLUGIN_FLAG_DISABLED));
    CKRV;

    {
        khm_size cb = 0;
        wchar_t * pl = NULL;
        size_t scb = 0;

        rv = khc_read_multi_string(csp_module, L"PluginList", NULL, &cb);
        if(rv != KHM_ERROR_TOO_LONG) {
            if (rv == KHM_ERROR_NOT_FOUND) {

                scb = cb = (cch + 1) * sizeof(wchar_t);
                pl = PMALLOC(cb);
                multi_string_init(pl, cb);
                rv = KHM_ERROR_SUCCESS;

                goto add_plugin_to_list;

            } else {
                goto _exit;
            }
        }

        cb += cch * sizeof(wchar_t);
        scb = cb;

        pl = PMALLOC(cb);

        rv = khc_read_multi_string(csp_module, L"PluginList", pl, &cb);
        if(KHM_FAILED(rv)) {
            if(pl)
                PFREE(pl);
            goto _exit;
        }

    add_plugin_to_list:

        if(!multi_string_find(pl, plugin->name, 0)) {
            multi_string_append(pl, &scb, plugin->name);
            rv = khc_write_multi_string(csp_module, L"PluginList", pl);
        }

        PFREE(pl);
        CKRV;
    }

#undef CKRV

_exit:
    if(csp_plugin)
        khc_close_space(csp_plugin);
    if(csp_module)
        khc_close_space(csp_module);

    return rv;
}
Exemple #7
0
/*! \internal
  \brief Initialize a plugin

  \note If kmmint_init_plugin() is called on a plugin, then kmmint_exit_plugin()
      \b must be called for the plugin.

  \note Should only be called from the context of the registrar thread */
void kmmint_init_plugin(kmm_plugin_i * p) {
    DWORD dummy;
    khm_handle csp_plugin   = NULL;
    khm_handle csp_plugins  = NULL;
    khm_int32 t;

    /* the following will be undone in kmmint_exit_plugin() */
    kmm_hold_plugin(kmm_handle_from_plugin(p));

    EnterCriticalSection(&cs_kmm);
    if(p->state != KMM_PLUGIN_STATE_REG &&
        p->state != KMM_PLUGIN_STATE_HOLD)
    {
        LeaveCriticalSection(&cs_kmm);
        goto _exit;
    }

    _begin_task(0);
    _report_mr1(KHERR_NONE, MSG_IP_TASK_DESC, _cstr(p->p.name));
    _describe();

    if(p->state == KMM_PLUGIN_STATE_HOLD) {
        /* if this plugin was held, then we already had a hold
           from the initial attempt to start the plugin.  Undo
           the hold we did a few lines earlier. */
        kmm_release_plugin(kmm_handle_from_plugin(p));

        /* same for the plugin count for the module. */
#ifdef DEBUG
        assert(p->flags & KMM_PLUGIN_FLAG_IN_MODCOUNT);
#endif
        p->module->plugin_count--;
        p->flags &= ~KMM_PLUGIN_FLAG_IN_MODCOUNT;
    }

    p->state = KMM_PLUGIN_STATE_PREINIT;

    kmmint_delist_plugin(p);
    kmmint_list_plugin(p);

    LeaveCriticalSection(&cs_kmm);

    if(KHM_FAILED(kmm_get_plugins_config(0, &csp_plugins))) {
        _report_mr0(KHERR_ERROR, MSG_IP_GET_CONFIG);

        p->state = KMM_PLUGIN_STATE_FAIL_UNKNOWN;
        goto _exit;
    }

    if(KHM_FAILED(kmm_get_plugin_config(p->p.name, 0, &csp_plugin))) {
        if(KHM_FAILED(kmm_register_plugin(&(p->p), 0))) {
            _report_mr0(KHERR_ERROR, MSG_IP_NOT_REGISTERED);

            p->state = KMM_PLUGIN_STATE_FAIL_NOT_REGISTERED;
            goto _exit;
        }
        
        if(KHM_FAILED(kmm_get_plugin_config(p->p.name, 0, &csp_plugin))) {
            _report_mr0(KHERR_ERROR, MSG_IP_NOT_REGISTERED);

            p->state = KMM_PLUGIN_STATE_FAIL_NOT_REGISTERED;
            goto _exit;
        }
    }

    if (KHM_SUCCEEDED(khc_read_int32(csp_plugin, L"Disabled", &t)) && t) {
        p->flags |= KMM_PLUGIN_FLAG_DISABLED;
        p->state = KMM_PLUGIN_STATE_FAIL_DISABLED;
        goto _exit;
    }

#if 0
    /*TODO: check the failure count and act accordingly */
    if(KHM_SUCCEEDED(khc_read_int32(csp_plugin, L"FailureCount", &t)) && (t > 0)) {
    }
#endif

    EnterCriticalSection(&cs_kmm);

    p->n_depends = 0;
    p->n_unresolved = 0;
    
    do {
        wchar_t * deps = NULL;
        wchar_t * d;
        khm_size sz = 0;

        if(khc_read_multi_string(csp_plugin, L"Dependencies", 
                                 NULL, &sz) != KHM_ERROR_TOO_LONG)
            break;

        deps = PMALLOC(sz);
        if(KHM_FAILED(khc_read_multi_string(csp_plugin, L"Dependencies", 
                                            deps, &sz))) {
            if(deps)
                PFREE(deps);
            break;
        }

        for(d = deps; d && *d; d = multi_string_next(d)) {
            kmm_plugin_i * pd;
            int i;

            pd = kmmint_get_plugin_i(d);

            if(pd->state == KMM_PLUGIN_STATE_NONE) {
                /* the dependant was not previously known */
                pd->state = KMM_PLUGIN_STATE_PLACEHOLDER;
            }

            for(i=0; i < pd->n_dependants; i++) {
                if(pd->dependants[i] == p)
                    break;
            }

            if(i >= pd->n_dependants) {
                if( pd->n_dependants >= KMM_MAX_DEPENDANTS ) {
                    /*TODO: handle this gracefully */
                    RaiseException(1, EXCEPTION_NONCONTINUABLE, 0, NULL);
                }

                /* released in kmmint_free_plugin() */
                kmm_hold_plugin(kmm_handle_from_plugin(p));
                pd->dependants[pd->n_dependants] = p;
                pd->n_dependants++;
            }

            p->n_depends++;

            if(pd->state != KMM_PLUGIN_STATE_RUNNING) {
                p->n_unresolved++;
            }
        }

        if(p->n_unresolved > 0) {
            p->state = KMM_PLUGIN_STATE_HOLD;
        }

        PFREE(deps);

    } while(FALSE);

#ifdef DEBUG
    assert(!(p->flags & KMM_PLUGIN_FLAG_IN_MODCOUNT));
#endif
    p->flags |= KMM_PLUGIN_FLAG_IN_MODCOUNT;
    p->module->plugin_count++;

    LeaveCriticalSection(&cs_kmm);

    if(p->state == KMM_PLUGIN_STATE_HOLD) {
        _report_mr1(KHERR_INFO, MSG_IP_HOLD, _dupstr(p->p.name));

        goto _exit_post;
    }

    kmmint_add_to_plugin_queue(p);

    p->ht_thread = CreateThread(NULL,
                                0,
                                kmmint_plugin_broker,
                                (LPVOID) p,
                                CREATE_SUSPENDED,
                                &dummy);

    p->state = KMM_PLUGIN_STATE_INIT;

    ResumeThread(p->ht_thread);

_exit_post:
    if(csp_plugin != NULL)
        khc_close_space(csp_plugin);

    if(csp_plugins != NULL)
        khc_close_space(csp_plugins);

    _report_mr2(KHERR_INFO, MSG_IP_STATE, 
                _dupstr(p->p.name), _int32(p->state));

    _end_task();
    
    return;

    /* jump here if an error condition happens before the plugin
       broker thread starts and the plugin should be unloaded */

_exit:
    if(csp_plugin != NULL)
        khc_close_space(csp_plugin);
    if(csp_plugins != NULL)
        khc_close_space(csp_plugins);

    _report_mr2(KHERR_WARNING, MSG_IP_EXITING, 
                _dupstr(p->p.name), _int32(p->state));
    _end_task();


#ifdef ASYNC_PLUGIN_UNLOAD_ON_FAILURE

    kmm_hold_plugin(kmm_handle_from_plugin(p));

    kmq_post_message(KMSG_KMM, KMSG_KMM_I_REG, KMM_REG_EXIT_PLUGIN, (void *) p);

#else

    kmmint_exit_plugin(p);

#endif
}
Exemple #8
0
/* Handler for system messages.  The only two we handle are
   KMSG_SYSTEM_INIT and KMSG_SYSTEM_EXIT. */
khm_int32 KHMAPI
handle_kmsg_system(khm_int32 msg_type,
                   khm_int32 msg_subtype,
                   khm_ui_4  uparam,
                   void *    vparam) {
    khm_int32 rv = KHM_ERROR_SUCCESS;

    switch (msg_subtype) {

        /* This is the first message that will be received by a
           plugin.  We use it to perform initialization operations
           such as registering any credential types, data types and
           attributes. */
    case KMSG_SYSTEM_INIT:
        {
            kcdb_credtype ct;
            wchar_t short_desc[KCDB_MAXCCH_SHORT_DESC];
            wchar_t long_desc[KCDB_MAXCCH_LONG_DESC];
            khui_config_node cnode;
            khui_config_node_reg creg;
            kcdb_attrib attr;
            khm_handle csp_plugin = NULL;
            khm_handle csp_plugins = NULL;

#ifdef BUILD_KRBCOMPAT
            /* If we don't have a Kerberos backend, then we can't
             * function. */
            if (!DelayLoadHeimdal()) {
		_reportf("Can't initialize a Kerberos backend.  LastError=%d", GetLastError());
                return KHM_ERROR_NOT_FOUND;
            }
#endif

#if KH_VERSION_API < 12

            do {
                khm_version libver;
                khm_ui_4 apiver;

                khm_get_lib_version(&libver, &apiver);

                if (apiver < 7)
                    break;

                hm_netidmgr = LoadLibrary(NIMDLLNAME);

                if (hm_netidmgr == NULL)
                    break;

#if KH_VERSION_API < 7
                pkhui_action_lock = (void (KHMAPI *)(void))
                    GetProcAddress(hm_netidmgr, API_khui_action_lock);
                pkhui_action_unlock = (void (KHMAPI *)(void))
                    GetProcAddress(hm_netidmgr, API_khui_action_unlock);
                pkhui_refresh_actions = (void (KHMAPI *)(void))
                    GetProcAddress(hm_netidmgr, API_khui_refresh_actions);
                pkhui_request_UI_callback = (khm_int32 (KHMAPI *)(khm_ui_callback, void *))
                    GetProcAddress(hm_netidmgr, API_khui_request_UI_callback);
#endif
                pkhui_cw_get_primary_id = (khm_int32 (KHMAPI *)(khui_new_creds *, khm_handle *))
                    GetProcAddress(hm_netidmgr, API_khui_cw_get_primary_id);
                pkhui_cw_get_result = (khm_int32 (KHMAPI *)(khui_new_creds *))
                    GetProcAddress(hm_netidmgr, API_khui_cw_get_result);
                pkhui_cw_get_subtype = (khui_nc_subtype (KHMAPI *)(khui_new_creds *))
                    GetProcAddress(hm_netidmgr, API_khui_cw_get_subtype);
                pkhui_cw_get_ctx = (khui_action_context * (KHMAPI *)(khui_new_creds *))
                    GetProcAddress(hm_netidmgr, API_khui_cw_get_ctx);
                pkcdb_get_resource = (khm_int32 (KHMAPI *)(khm_handle, kcdb_resource_id,
                                                           khm_int32, khm_int32 *,
                                                           void *, void *, khm_size *))
                    GetProcAddress(hm_netidmgr, API_kcdb_get_resource);
            } while (FALSE);

            if (pkhui_cw_get_primary_id == NULL)
              pkhui_cw_get_primary_id = int_khui_cw_get_primary_id;

            if (pkhui_cw_get_result == NULL)
                pkhui_cw_get_result = int_khui_cw_get_result;

            if (pkhui_cw_get_subtype == NULL)
                pkhui_cw_get_subtype = int_khui_cw_get_subtype;

            if (pkhui_cw_get_ctx == NULL)
                pkhui_cw_get_ctx = int_khui_cw_get_ctx;

            if (pkcdb_get_resource == NULL)
                pkcdb_get_resource = int_kcdb_get_resource;
#endif

            /* Add the icon now.  On NIM v2.x, doing so after tokens
               were reported may result in a deadlock as we try to
               switch to the UI thread and the UI thread is blocked on
               a resource request to this plug-in. */
            kca_icon_set_state(NULL);

            /* First and foremost, we need to register a credential
               type. */
            ZeroMemory(&ct, sizeof(ct));
            ct.id = KCDB_CREDTYPE_AUTO;
            ct.name = MYCREDTYPE_NAMEW;
            ct.short_desc = short_desc;
            ct.long_desc = long_desc;

            short_desc[0] = L'\0';
            LoadString(hResModule, IDS_CT_SHORT_DESC,
                       short_desc, ARRAYLENGTH(short_desc));

            long_desc[0] = L'\0';
            LoadString(hResModule, IDS_CT_LONG_DESC,
                       long_desc, ARRAYLENGTH(long_desc));

            ct.icon = NULL;     /* We skip the icon for now, but you
                                   can assign a handle to an icon
                                   here.  The icon will be used to
                                   represent the credentials type.*/

            kmq_create_subscription(plugin_msg_proc, &ct.sub);

            ct.is_equal = cred_is_equal;

            rv = kcdb_credtype_register(&ct, &credtype_id);

            /* We create a global credential set that we use in the
               plug-in thread.  This alleviates the need to create one
               everytime we need one. Keep in mind that this should
               only be used in the plug-in thread and should not be
               touched from the UI thread or any other thread. */
            kcdb_credset_create(&g_credset);

            /* TODO: Perform additional initialization operations. */

            /* Register our attributes */

            ZeroMemory(&attr, sizeof(attr));

            attr.name = ATTRNAME_KCA_AUTHREALM;
            attr.id = KCDB_ATTR_INVALID;
            attr.alt_id = KCDB_ATTR_INVALID;
            attr.flags = 0;
            attr.type = KCDB_TYPE_STRING;
            attr.short_desc = short_desc;
            attr.long_desc = long_desc;
            attr.compute_cb = NULL;
            attr.compute_min_cbsize = 0;
            attr.compute_max_cbsize = 0;

            LoadString(hResModule, IDS_ATTR_REALM_SHORT_DESC,
                       short_desc, ARRAYLENGTH(short_desc));
            LoadString(hResModule, IDS_ATTR_REALM_LONG_DESC,
                       long_desc, ARRAYLENGTH(long_desc));

            rv = kcdb_attrib_register(&attr, &attr_id_auth_realm);
            if (KHM_FAILED(rv))
                break;

            attr.name = ATTRNAME_SUBJECT_EMAIL;

            LoadString(hResModule, IDS_ATTR_SUBJECT_EMAIL_SHORT_DESC,
                       short_desc, ARRAYLENGTH(short_desc));
            LoadString(hResModule, IDS_ATTR_SUBJECT_EMAIL_LONG_DESC,
                       long_desc, ARRAYLENGTH(long_desc));

            rv = kcdb_attrib_register(&attr, &attr_id_subj_email);
            if (KHM_FAILED(rv))
                break;

            attr.name = ATTRNAME_SUBJECT_DISPLAY;

            LoadString(hResModule, IDS_ATTR_SUBJECT_SHORT_DESC,
                       short_desc, ARRAYLENGTH(short_desc));
            LoadString(hResModule, IDS_ATTR_SUBJECT_LONG_DESC,
                       long_desc, ARRAYLENGTH(long_desc));

            rv = kcdb_attrib_register(&attr, &attr_id_subj_display);
            if (KHM_FAILED(rv))
                break;

            attr.name = ATTRNAME_ISSUER_DISPLAY;

            LoadString(hResModule, IDS_ATTR_ISSUER_SHORT_DESC,
                       short_desc, ARRAYLENGTH(short_desc));
            LoadString(hResModule, IDS_ATTR_ISSUER_LONG_DESC,
                       long_desc, ARRAYLENGTH(long_desc));

            rv = kcdb_attrib_register(&attr, &attr_id_issuer_display);
            if (KHM_FAILED(rv))
                break;

            attr.name = ATTRNAME_ISSUER_NAME;
            attr.flags = KCDB_ATTR_FLAG_HIDDEN;
            attr.type = KCDB_TYPE_DATA;
            attr.short_desc = NULL;
            attr.long_desc = NULL;

            rv = kcdb_attrib_register(&attr, &attr_id_issuer_name);
            if (KHM_FAILED(rv))
                break;

            attr.name = ATTRNAME_SERIAL;

            rv = kcdb_attrib_register(&attr, &attr_id_serial_number);
            if (KHM_FAILED(rv))
                break;

            /* List the credentials that are already here */
            kca_list_creds();

            /* Now we register our configuration panels. */

#ifdef GENERAL_CONFIG_PANEL
            /* This configuration panel is the one that controls
               general options.  We leave the identity specific and
               identity defaults for other configuration panels. */

            ZeroMemory(&creg, sizeof(creg));

            short_desc[0] = L'\0';

            LoadString(hResModule, IDS_CFG_SHORT_DESC,
                       short_desc, ARRAYLENGTH(short_desc));

            long_desc[0] = L'\0';

            LoadString(hResModule, IDS_CFG_LONG_DESC,
                       long_desc, ARRAYLENGTH(long_desc));

            creg.name = CONFIGNODE_MAIN;
            creg.short_desc = short_desc;
            creg.long_desc = long_desc;
            creg.h_module = hResModule;
            creg.dlg_template = MAKEINTRESOURCE(IDD_CONFIG);
            creg.dlg_proc = config_dlgproc;
            creg.flags = 0;

            khui_cfg_register(NULL, &creg);
#endif

            /* Now we do the identity specific and identity default
               configuration panels. "KhmIdentities" is a predefined
               configuration node under which all the identity spcific
               configuration is managed. */

            if (KHM_FAILED(khui_cfg_open(NULL, L"KhmIdentities", &cnode))) {
                /* this should always work */
                assert(FALSE);
                rv = KHM_ERROR_NOT_FOUND;
                break;
            }

            /* First the tab panel for defaults for all identities */

            ZeroMemory(&creg, sizeof(creg));

            short_desc[0] = L'\0';
            LoadString(hResModule, IDS_CFG_IDS_SHORT_DESC,
                       short_desc, ARRAYLENGTH(short_desc));
            long_desc[0] = L'\0';
            LoadString(hResModule, IDS_CFG_IDS_LONG_DESC,
                       long_desc, ARRAYLENGTH(long_desc));

            creg.name = CONFIGNODE_ALL_ID;
            creg.short_desc = short_desc;
            creg.long_desc = long_desc;
            creg.h_module = hResModule;
            creg.dlg_template = MAKEINTRESOURCE(IDD_CONFIG_IDS);
            creg.dlg_proc = config_ids_dlgproc;
            creg.flags = KHUI_CNFLAG_SUBPANEL;

            khui_cfg_register(cnode, &creg);

            /* Now the panel for per identity configuration */

            ZeroMemory(&creg, sizeof(creg));

            short_desc[0] = L'\0';
            LoadString(hResModule, IDS_CFG_ID_SHORT_DESC,
                       short_desc, ARRAYLENGTH(short_desc));
            long_desc[0] = L'\0';
            LoadString(hResModule, IDS_CFG_ID_LONG_DESC,
                       long_desc, ARRAYLENGTH(long_desc));

            creg.name = CONFIGNODE_PER_ID;
            creg.short_desc = short_desc;
            creg.long_desc = long_desc;
            creg.h_module = hResModule;
            creg.dlg_template = MAKEINTRESOURCE(IDD_CONFIG_ID);
            creg.dlg_proc = config_id_dlgproc;
            creg.flags = KHUI_CNFLAG_SUBPANEL | KHUI_CNFLAG_INSTANCE;

            khui_cfg_register(cnode, &creg);

            khui_cfg_release(cnode);

            /* load the schema */
            if (KHM_SUCCEEDED(kmm_get_plugins_config(0, &csp_plugins))) {
                khc_load_schema(csp_plugins, plugin_schema);
                khc_close_space(csp_plugins);
            }

            /* open the plug-in and parameter configuration spaces */
            if (KHM_SUCCEEDED(kmm_get_plugin_config(MYPLUGIN_NAMEW,
                                                    KHM_FLAG_CREATE,
                                                    &csp_plugin))) {
                khc_open_space(csp_plugin, L"Parameters", KHM_FLAG_CREATE,
                               &csp_params);

                khc_close_space(csp_plugin);
            }

            /* try to install the kpkcs11 plugin now */
            install_kpkcs11_plugin();

            /* register the "KCA Help" menu item, so that we can add
               the plug-in menu item to the Help menu. */
            {
                khm_handle h_sub = NULL;

#if KH_VERSION_API < 7

                if (pkhui_action_lock == NULL ||
                    pkhui_action_unlock == NULL ||
                    pkhui_refresh_actions == NULL ||
                    pkhui_request_UI_callback == NULL)

                    goto no_custom_help;

#endif

                kmq_create_subscription(plugin_msg_proc, &h_sub);

                LoadString(hResModule, IDS_ACTION_KCA_HELP,
                           short_desc, ARRAYLENGTH(short_desc));
                LoadString(hResModule, IDS_ACTION_KCA_HELP_TT,
                           long_desc, ARRAYLENGTH(long_desc));

                action_id_kca_help = khui_action_create(NULL,
                                                        short_desc,
                                                        long_desc,
                                                        NULL,
                                                        KHUI_ACTIONTYPE_TRIGGER,
                                                        h_sub);

                if (action_id_kca_help != 0) {
                    khm_size s;
                    khm_size i;
                    khui_menu_def * help_menu;
                    khm_boolean refresh = FALSE;

                    khui_action_lock();

                    help_menu = khui_find_menu(KHUI_MENU_HELP);
                    if (help_menu) {
                        s = khui_menu_get_size(help_menu);

                        for (i=0; i < s; i++) {
                            khui_action_ref * aref;

                            aref = khui_menu_get_action(help_menu, i);

                            if (aref && !(aref->flags & KHUI_ACTIONREF_PACTION) &&
                                aref->action == KHUI_ACTION_HELP_INDEX) {

                                khui_menu_insert_action(help_menu,
                                                        i + 1,
                                                        action_id_kca_help,
                                                        0);
                                refresh = TRUE;
                                break;
                            }
                        }
                    }

                    khui_action_unlock();

                    if (refresh)
                        khui_refresh_actions();
                }

#if KH_VERSION_API < 7
            no_custom_help:
                ;
#endif
            }
        }
        break;

        /* This is the last message that will be received by the
           plugin. */
    case KMSG_SYSTEM_EXIT:
        {
            khui_config_node cnode;
            khui_config_node cn_idents;
            khm_int32 attr_id;

            kca_remove_icon();

            /* It should not be assumed that initialization of the
               plugin went well at this point since we receive a
               KMSG_SYSTEM_EXIT even if the initialization failed. */

            /* Try to remove the KCA plug-in action from Help menu if
               it was successfully registered.  Also, delete the
               action. */
            if (action_id_kca_help != 0) {

                khui_menu_def * help_menu;
                khm_boolean menu_changed = FALSE;

                khui_action_lock();

                help_menu = khui_find_menu(KHUI_MENU_HELP);
                if (help_menu) {
                    khm_size s;
                    khm_size i;

                    s = khui_menu_get_size(help_menu);
                    for (i=0; i < s; i++) {
                        khui_action_ref * aref = khui_menu_get_action(help_menu, i);

                        if (aref && !(aref->flags & KHUI_ACTIONREF_PACTION) &&
                            aref->action == action_id_kca_help) {

                            khui_menu_remove_action(help_menu, i);
                            menu_changed = TRUE;
                            break;

                        }
                    }
                }

                khui_action_delete(action_id_kca_help);

                khui_action_unlock();

                if (menu_changed)
                    khui_refresh_actions();

                action_id_kca_help = 0;
            }

            if (credtype_id != KCDB_CREDTYPE_INVALID) {
                kcdb_credtype_unregister(credtype_id);
                credtype_id = KCDB_CREDTYPE_INVALID;
            }

            if (g_credset) {
                kcdb_credset_delete(g_credset);
                g_credset = NULL;
            }

            /* Now unregister any configuration nodes we registered. */

            if (KHM_SUCCEEDED(khui_cfg_open(NULL, CONFIGNODE_MAIN, &cnode))) {
                khui_cfg_remove(cnode);
                khui_cfg_release(cnode);
            }

            if (KHM_SUCCEEDED(khui_cfg_open(NULL, L"KhmIdentities", &cn_idents))) {
                if (KHM_SUCCEEDED(khui_cfg_open(cn_idents,
                                                CONFIGNODE_ALL_ID,
                                                &cnode))) {
                    khui_cfg_remove(cnode);
                    khui_cfg_release(cnode);
                }

                if (KHM_SUCCEEDED(khui_cfg_open(cn_idents,
                                                CONFIGNODE_PER_ID,
                                                &cnode))) {
                    khui_cfg_remove(cnode);
                    khui_cfg_release(cnode);
                }

                khui_cfg_release(cn_idents);
            }

            if (KHM_SUCCEEDED(kcdb_attrib_get_id(ATTRNAME_KCA_AUTHREALM,
                                                 &attr_id)))
                kcdb_attrib_unregister(attr_id);

            if (KHM_SUCCEEDED(kcdb_attrib_get_id(ATTRNAME_SUBJECT_EMAIL,
                                                 &attr_id)))
                kcdb_attrib_unregister(attr_id);

            if (KHM_SUCCEEDED(kcdb_attrib_get_id(ATTRNAME_SUBJECT_DISPLAY,
                                                 &attr_id)))
                kcdb_attrib_unregister(attr_id);

            if (KHM_SUCCEEDED(kcdb_attrib_get_id(ATTRNAME_ISSUER_DISPLAY,
                                                 &attr_id)))
                kcdb_attrib_unregister(attr_id);

            if (KHM_SUCCEEDED(kcdb_attrib_get_id(ATTRNAME_ISSUER_NAME,
                                                 &attr_id)))
                kcdb_attrib_unregister(attr_id);

            if (KHM_SUCCEEDED(kcdb_attrib_get_id(ATTRNAME_SERIAL,
                                                 &attr_id)))
                kcdb_attrib_unregister(attr_id);

            if (csp_params) {
                khc_close_space(csp_params);
                csp_params = NULL;
            }

#if KH_VERSION_API < 12
            if (hm_netidmgr)
                FreeLibrary(hm_netidmgr);

            pkhui_cw_get_primary_id = NULL;
#endif

#if KH_VERSION_API < 7
            pkhui_action_lock = NULL;
            pkhui_action_unlock = NULL;
            pkhui_refresh_actions = NULL;
            pkhui_request_UI_callback = NULL;
#endif

            /* TODO: Perform additional uninitialization
               operations. */
        }
        break;
    }

    return rv;
}