Beispiel #1
0
KHMEXP khm_int32   KHMAPI
kmm_get_module_info_i(kmm_module vm, kmm_module_info * info) {
    kmm_module_i * m;
    khm_int32 rv;

    EnterCriticalSection(&cs_kmm);
    if (!kmm_is_module(vm) || !info)
        rv = KHM_ERROR_INVALID_PARAM;
    else {
        m = kmm_module_from_handle(vm);

        ZeroMemory(info, sizeof(*info));

        info->reg.name = m->name;
        info->reg.path = m->path;
        info->reg.vendor = m->vendor;

        info->reg.n_plugins = m->plugin_count;

        info->state = m->state;

        info->h_module = vm;

        info->file_version = m->file_version;
        info->product_version = m->prod_version;
        kmm_hold_module(vm);

        rv = KHM_ERROR_SUCCESS;
    }
    LeaveCriticalSection(&cs_kmm);

    return rv;
}
/*! \internal
  \brief Uninitialize a plugin

  In addition to terminating the thread, and removing p from the
  linked list and hashtable, it also frees up p.
   
  \note Should only be called from the context of the registrar thread. */
void kmmint_exit_plugin(kmm_plugin_i * p) {
    int np;
    khm_boolean release_plugin = TRUE;

    if(p->state == KMM_PLUGIN_STATE_RUNNING ||
       p->state == KMM_PLUGIN_STATE_INIT) {

        kmq_post_thread_quit_message(p->tid_thread, 0, NULL);
        /* when we post the quit message to the plugin thread, the plugin
           broker terminates the plugin and posts a EXIT_PLUGIN message,
           which calls this function again.  We just exit here because
           the EXIT_PLUGIN message will end up calling us again momentarily */
        return;

    }

    if(p->ht_thread) {
        /* wait for the thread to terminate */
        WaitForSingleObject(p->ht_thread, INFINITE);
        p->ht_thread = NULL;
    }

    EnterCriticalSection(&cs_kmm);

    /* undo reference count done in kmmint_init_plugin() */
    if(p->flags & KMM_PLUGIN_FLAG_IN_MODCOUNT) {

        np = --(p->module->plugin_count);
        p->flags &= ~KMM_PLUGIN_FLAG_IN_MODCOUNT;

    } else {
        /* the plugin was not included in the module's plugin_count.
           We can't base a decision to unload the module based on this
           plugin exiting. */
        np = TRUE;
    }

    /* The plugin is in an error state.  We need to keep the plugin
       record intact so that the failure information is kept around.
       Also, we shouldn't release the plugin if it appears that
       kmmint_init_plugin() was never called for it. */
    if (p->state < KMM_PLUGIN_STATE_HOLD) {
        release_plugin = FALSE;
    }

    LeaveCriticalSection(&cs_kmm);

    if(!np) {
        /*  if this is the last plugin to exit, then notify the
            registrar that the module should be removed as well */
        kmm_hold_module(kmm_handle_from_module(p->module));
        kmq_post_message(KMSG_KMM, KMSG_KMM_I_REG, KMM_REG_EXIT_MODULE, (void *) p->module);
    }

    /* release the hold obtained in kmmint_init_plugin() */
    if (release_plugin)
        kmm_release_plugin(kmm_handle_from_plugin(p));
}
Beispiel #3
0
KHMEXP khm_int32   KHMAPI 
kmm_unload_module(kmm_module module) {

    if(!kmm_is_module(module))
        return KHM_ERROR_INVALID_PARAM;

    kmm_hold_module(module);
    kmq_post_message(KMSG_KMM, 
		     KMSG_KMM_I_REG, 
		     KMM_REG_EXIT_MODULE, 
		     (void *) kmm_module_from_handle(module));

    return KHM_ERROR_SUCCESS;
}
Beispiel #4
0
KHMEXP khm_int32   KHMAPI
kmm_provide_plugin(kmm_module module, kmm_plugin_reg * plugin)
{
    kmm_module_i * m;
    kmm_plugin_i * p;
    size_t cb_name = 0;
    size_t cb_desc = 0;
    size_t cb_dep = 0;

    m = kmm_module_from_handle(module);

    /* can only called when handing init_module() */
    if(m->state != KMM_MODULE_STATE_INIT)
        return KHM_ERROR_INVALID_OPERATION;

    if(!plugin ||
       FAILED(StringCbLength(plugin->name, KMM_MAXCB_NAME - sizeof(wchar_t),
                             &cb_name)) ||
       (plugin->description &&
        FAILED(StringCbLength(plugin->description,
                              KMM_MAXCB_DESC - sizeof(wchar_t),
                              &cb_desc))) ||
       (plugin->dependencies &&
        KHM_FAILED(multi_string_length_cb(plugin->dependencies,
                                          KMM_MAXCB_DEPS, &cb_dep)))) {
        return KHM_ERROR_INVALID_PARAM;
    }

    cb_name += sizeof(wchar_t);
    cb_desc += sizeof(wchar_t);

    p = kmmint_get_plugin_i(plugin->name);

    /* released below or in kmmint_init_module() */
    kmm_hold_plugin(kmm_handle_from_plugin(p));

    if(p->state != KMM_PLUGIN_STATE_NONE &&
        p->state != KMM_PLUGIN_STATE_PLACEHOLDER)
    {
        kmm_release_plugin(kmm_handle_from_plugin(p));
        return KHM_ERROR_DUPLICATE;
    }

    /* released when the plugin quits */
    kmm_hold_module(module);

    p->module = m;
    p->p.flags = plugin->flags;
    p->p.msg_proc = plugin->msg_proc;
    p->p.type = plugin->type;

    if(plugin->description) {
        p->p.description = PMALLOC(cb_desc);
        StringCbCopy(p->p.description, cb_desc, plugin->description);
    } else
        p->p.description = NULL;

    if(plugin->dependencies) {
        p->p.dependencies = PMALLOC(cb_dep);
        multi_string_copy_cb(p->p.dependencies, cb_dep, plugin->dependencies);
    } else
        p->p.dependencies = NULL;

    p->p.module = p->module->name;

    p->p.icon = plugin->icon;

    p->state = KMM_PLUGIN_STATE_REG;

    kmmint_delist_plugin(p);
    EnterCriticalSection(&cs_kmm);
    LPUSH(&(m->plugins), p);
    p->flags |= KMM_PLUGIN_FLAG_IN_MODLIST;
    LeaveCriticalSection(&cs_kmm);

    /* leave the plugin held because it is in the module's plugin list */
    return KHM_ERROR_SUCCESS;
}
Beispiel #5
0
KHMEXP khm_int32   KHMAPI kmm_load_module(wchar_t * modname, 
                                          khm_int32 flags, 
                                          kmm_module * result)
{
    kmm_module_i * m = NULL;
    kmm_module_i * mi;
    size_t cbsize;
    khm_int32 rv = KHM_ERROR_SUCCESS;

    if(FAILED(StringCbLength(modname, KMM_MAXCB_NAME, &cbsize)))
        return KHM_ERROR_INVALID_PARAM;
    cbsize += sizeof(wchar_t);

    EnterCriticalSection(&cs_kmm);
    mi = kmmint_find_module_i(modname);

    if(mi != NULL) {
        kmm_hold_module(kmm_handle_from_module(mi));
        /* check if the module has either failed to load either or if
        it has been terminated.  If so, we try once again to load the
        module. */
        if(!(flags & KMM_LM_FLAG_NOLOAD) && 
            (mi->state < 0 || mi->state == KMM_MODULE_STATE_EXITED)) 
        {
            mi->state = KMM_MODULE_STATE_PREINIT;
        }
    }
    LeaveCriticalSection(&cs_kmm);

    if(flags & KMM_LM_FLAG_NOLOAD) {
        if(result)
            *result = mi;
        else if(mi)
            kmm_release_module(kmm_handle_from_module(mi));

        return (mi)? KHM_ERROR_SUCCESS: KHM_ERROR_NOT_FOUND;
    }

    if(mi) {
        m = mi;
    } else {
        m = kmmint_get_module_i(modname);
        m->state = KMM_MODULE_STATE_PREINIT;
        kmm_hold_module(kmm_handle_from_module(m));
    }

    /* the module is already running or is already being
       worked on by the registrar */
    if(m->state != KMM_MODULE_STATE_PREINIT) {
        if(result)
            *result = kmm_handle_from_module(m);
        else
            kmm_release_module(kmm_handle_from_module(m));

        return KHM_ERROR_EXISTS;
    }

    kmmint_add_to_module_queue();

    if(flags & KMM_LM_FLAG_SYNC) {
        kmm_hold_module(kmm_handle_from_module(m));
        kmq_send_message(KMSG_KMM, 
                         KMSG_KMM_I_REG, 
                         KMM_REG_INIT_MODULE, 
                         (void*) m);
        if(m->state <= 0) {
            /* failed to load ? */
            if(m->state == KMM_MODULE_STATE_FAIL_NOT_FOUND)
                rv = KHM_ERROR_NOT_FOUND;
            else if(m->state == KMM_MODULE_STATE_FAIL_SIGNATURE)
                rv = KHM_ERROR_INVALID_SIGNATURE;
            else
                rv = KHM_ERROR_UNKNOWN;

            kmm_release_module(kmm_handle_from_module(m));
            if(result)
                *result = NULL;
        } else {
            if(result)
                *result = kmm_handle_from_module(m);
            else
                kmm_release_module(kmm_handle_from_module(m));
        }
    } else {
        kmm_hold_module(kmm_handle_from_module(m));
        kmq_post_message(KMSG_KMM, 
                         KMSG_KMM_I_REG, 
                         KMM_REG_INIT_MODULE, 
                         (void*) m);
        if(result)
            *result = kmm_handle_from_module(m);
        else
            kmm_release_module(kmm_handle_from_module(m));
    }

    return rv;
}
Beispiel #6
0
/*! \internal
  \brief Initialize a module

  \a m is not in the linked list yet.

  \note Should only be called from the context of the registrar thread. */
void kmmint_init_module(kmm_module_i * m) {
    HMODULE hm;
    init_module_t p_init_module;
    kmm_plugin_i * pi;
    khm_int32 rv;
    khm_handle csp_mod = NULL;
    khm_handle csp_mods = NULL;
    khm_size sz;
    khm_int32 i;

    /* error condition handling */
    BOOL exit_module = FALSE;
    BOOL release_module = TRUE;
    BOOL record_failure = FALSE;

    /* failure handling */
    khm_int32 max_fail_count = 0;
    khm_int64 fail_reset_time = 0;

    _begin_task(0);
    _report_mr1(KHERR_NONE, MSG_INIT_MODULE, _cstr(m->name));
    _describe();

    kmm_hold_module(kmm_handle_from_module(m));

    if(KHM_FAILED(kmm_get_modules_config(0, &csp_mods))) {
        _report_mr0(KHERR_ERROR, MSG_IM_GET_CONFIG);
        _location(L"kmm_get_modules_config()");

        m->state = KMM_MODULE_STATE_FAIL_UNKNOWN;
        goto _exit;
    }

    khc_read_int32(csp_mods, L"ModuleMaxFailureCount", &max_fail_count);
    khc_read_int64(csp_mods, L"ModuleFailureCountResetTime", &fail_reset_time);

    /* If the module is not in the pre-init state, we can't
       initialize it. */
    if(m->state != KMM_MODULE_STATE_PREINIT) {
        _report_mr1(KHERR_INFO, MSG_IM_NOT_PREINIT, _int32(m->state));
        goto _exit;
    }

    if(KHM_FAILED(kmm_get_module_config(m->name, 0, &csp_mod))) {
        _report_mr0(KHERR_ERROR, MSG_IM_NOT_REGISTERED);

        m->state = KMM_MODULE_STATE_FAIL_NOT_REGISTERED;
        goto _exit;
    }

    if(KHM_SUCCEEDED(khc_read_int32(csp_mod, L"Disabled", &i)) && i) {
        _report_mr0(KHERR_INFO, MSG_IM_DISABLED);

        m->state = KMM_MODULE_STATE_FAIL_DISABLED;
        goto _exit;
    }

    if(KHM_SUCCEEDED(khc_read_int32(csp_mod, L"NoUnload", &i)) && i) {
        m->flags |= KMM_MODULE_FLAG_NOUNLOAD;
    }

    if(KHM_SUCCEEDED(khc_read_int32(csp_mod, L"FailureCount", &i))) {
        khm_int64 tm;
        khm_int64 ct;
        FILETIME fct;
        khm_int32 last_reason = 0;

        /* reset the failure count if the failure count reset time
           period has elapsed */
        tm = 0;
        khc_read_int64(csp_mod, L"FailureTime", &tm);
        GetSystemTimeAsFileTime(&fct);

        ct = (FtToInt(&fct) - tm) / 10000000i64;

        if(tm > 0 && 
           ct > fail_reset_time) {
            i = 0;
            khc_write_int32(csp_mod, L"FailureCount", 0);
            khc_write_int64(csp_mod, L"FailureTime", 0);
        }

        khc_read_int32(csp_mod, L"FailureReason", &last_reason);

        /* did we exceed the max failure count?  However, we ignore
           the max failure count if the reason why it didn't load the
           last time was because the module wasn't found. */
        if(i > max_fail_count && 
           last_reason != KMM_MODULE_STATE_FAIL_NOT_FOUND) {
            /* failed too many times */
            _report_mr0(KHERR_INFO, MSG_IM_MAX_FAIL);

            m->state = KMM_MODULE_STATE_FAIL_MAX_FAILURE;
            goto _exit;
        }
    }

    if(khc_read_string(csp_mod, L"ImagePath", NULL, &sz) == 
       KHM_ERROR_TOO_LONG) {
        if(m->path)
            PFREE(m->path);
        m->path = PMALLOC(sz);
        khc_read_string(csp_mod, L"ImagePath", m->path, &sz);
    } else {
        _report_mr0(KHERR_ERROR, MSG_IM_NOT_REGISTERED);

        m->state = KMM_MODULE_STATE_FAIL_NOT_REGISTERED;
        goto _exit;
    }

    rv = kmmint_read_module_info(m);

    if (KHM_FAILED(rv)) {
        if (rv == KHM_ERROR_INCOMPATIBLE) {
            _report_mr0(KHERR_ERROR, MSG_IM_INCOMPATIBLE);

            m->state = KMM_MODULE_STATE_FAIL_INCOMPAT;
        } else if (rv == KHM_ERROR_NOT_FOUND) {
            _report_mr1(KHERR_ERROR, MSG_IM_NOT_FOUND, _dupstr(m->path));

            m->state = KMM_MODULE_STATE_FAIL_NOT_FOUND;
        } else {
            _report_mr0(KHERR_ERROR, MSG_IM_INVALID_MODULE);

            m->state = KMM_MODULE_STATE_FAIL_INV_MODULE;
        }
        goto _exit;
    }

    /* check again */
    if(m->state != KMM_MODULE_STATE_PREINIT) {
        _report_mr0(KHERR_ERROR, MSG_IM_NOT_PREINIT);

        goto _exit;
    }

    /* from this point on, we must record any failure codes */
    record_failure = TRUE;

    hm = LoadLibrary(m->path);
    if(!hm) {
        m->h_module = NULL;
        m->state = KMM_MODULE_STATE_FAIL_NOT_FOUND;

        _report_mr1(KHERR_ERROR, MSG_IM_NOT_FOUND, _dupstr(m->path));

        goto _exit;
    }

    /* from this point on, we need to discard the module through
       exit_module */
    ResetEvent(evt_exit);

    kmm_active_modules++;

    release_module = FALSE;
    exit_module = TRUE;

    m->flags |= KMM_MODULE_FLAG_LOADED;
    m->h_module = hm;

    /* TODO: check signatures */

    p_init_module = (init_module_t) GetProcAddress(hm, EXP_INIT_MODULE);

    if(!p_init_module) {
        _report_mr1(KHERR_ERROR, MSG_IM_NO_ENTRY, _cstr(EXP_INIT_MODULE));

        m->state = KMM_MODULE_STATE_FAIL_INVALID;
        goto _exit;
    }

    m->state = KMM_MODULE_STATE_INIT;

    /* call init_module() */
    rv = (*p_init_module)(kmm_handle_from_module(m));

    m->flags |= KMM_MODULE_FLAG_INITP;

    if(KHM_FAILED(rv)) {
        _report_mr1(KHERR_ERROR, MSG_IM_INIT_FAIL, _int32(rv));

        m->state = KMM_MODULE_STATE_FAIL_LOAD;
        goto _exit;
    }

    if(!m->plugins) {
        _report_mr0(KHERR_ERROR, MSG_IM_NO_PLUGINS);

        m->state = KMM_MODULE_STATE_FAIL_NO_PLUGINS;
        record_failure = FALSE;
        goto _exit;
    }

    m->state = KMM_MODULE_STATE_INITPLUG;

    do {
        LPOP(&(m->plugins), &pi);
        if(pi) {
            pi->flags &= ~KMM_PLUGIN_FLAG_IN_MODLIST;
            kmmint_init_plugin(pi);

            /* release the hold obtained in kmm_provide_plugin() */
            kmm_release_plugin(kmm_handle_from_plugin(pi));
        }
    } while(pi);

    if(!m->plugin_count) {
        /* We don't want to report this case.  This usually means that
           the plugins that were provided by the module were
           disabled. */
#ifdef REPORT_EMPTY_MODULES
        _report_mr0(KHERR_ERROR, MSG_IM_NO_PLUGINS);

        m->state = KMM_MODULE_STATE_FAIL_NO_PLUGINS;
#endif
        record_failure = FALSE;
        goto _exit;
    }

    m->state = KMM_MODULE_STATE_RUNNING;

    exit_module = FALSE;
    record_failure = FALSE;

 _exit:
    if(csp_mod) {
        if(record_failure) {
            FILETIME fct;

            i = 0;
            khc_read_int32(csp_mod, L"FailureCount", &i);
            i++;
            khc_write_int32(csp_mod, L"FailureCount", i);

            if(i==1) { /* first fault */
                GetSystemTimeAsFileTime(&fct);
                khc_write_int64(csp_mod, L"FailureTime", FtToInt(&fct));
            }

            khc_write_int32(csp_mod, L"FailureReason", m->state);
        }
        khc_close_space(csp_mod);
    }

    if(csp_mods)
        khc_close_space(csp_mods);

    _report_mr2(KHERR_INFO, MSG_IM_MOD_STATE, 
                _dupstr(m->name), _int32(m->state));

    kmmint_remove_from_module_queue();

    /* if something went wrong after init_module was called on the
       module code, we need to call exit_module */
    if(exit_module)
        kmmint_exit_module(m);

    if(release_module)
        kmm_release_module(kmm_handle_from_module(m));

    if (kherr_is_error()) {
        kherr_context * c;
        kherr_event * err_e = NULL;
        kherr_event * warn_e = NULL;
        kherr_event * e;

        c = kherr_peek_context();
        err_e = kherr_get_err_event(c);
        for(e = kherr_get_first_event(c);
            e;
            e = kherr_get_next_event(e)) {
            if (e != err_e &&
                e->severity == KHERR_WARNING) {
                warn_e = e;
                break;
            }
        }

        kherr_evaluate_event(err_e);
        if (warn_e)
            kherr_evaluate_event(warn_e);

        kherr_clear_error();

        e = kherr_report(KHERR_ERROR,
                         (wchar_t *) MSG_IMERR_TITLE,
                         KHERR_FACILITY,
                         NULL,
                         err_e->long_desc,
                         ((warn_e)? (wchar_t *)MSG_IMERR_SUGGEST: NULL),
                         KHERR_FACILITY_ID,
                         KHERR_SUGGEST_NONE,
                         _cstr(m->name),
                         ((warn_e)? _cstr(warn_e->long_desc):_vnull()),
                         _vnull(),_vnull(),
                         KHERR_RF_MSG_SHORT_DESC |
                         ((warn_e)? KHERR_RF_MSG_SUGGEST: 0),
                         KHERR_HMODULE);

        kherr_evaluate_event(e);

        kherr_release_context(c);
    }

    _end_task();
}