Пример #1
0
khm_int32
kmmint_read_module_info(kmm_module_i * m) {
    /* the only fields we can count on at this point are m->name and
       m->path */
    DWORD t;
    size_t cb;
    WORD lang;
    khm_int32 rv = KHM_ERROR_SUCCESS;
    struct lang_code *languages;
    int n_languages;
    int i;
    wchar_t resname[256];       /* the resource names are a lot shorter */
    wchar_t * r;
    VS_FIXEDFILEINFO *vff;
    UINT c;

    assert(m->name);
    assert(m->path);

    t = TRUE;
    cb = GetFileVersionInfoSize(m->path,
                                &t);
    /* if successful, cb gets the size in bytes of the version info
       structure and sets t to zero */
    if (t) {
        return KHM_ERROR_NOT_FOUND;
    } else if (cb == 0) {
        _report_mr1(KHERR_WARNING, MSG_RMI_NOT_FOUND, _dupstr(m->path));
        return KHM_ERROR_INVALID_PARAM;
    }

    if (m->version_info) {
        PFREE(m->version_info);
        m->version_info = NULL;
    }

    m->version_info = PMALLOC(cb);
#ifdef DEBUG
    assert(m->version_info);
#endif

    if(!GetFileVersionInfo(m->path,
                           t, (DWORD) cb, m->version_info)) {
        rv = KHM_ERROR_NOT_FOUND;
        _report_mr1(KHERR_WARNING, MSG_RMI_NOT_FOUND, _dupstr(m->path));
        _location(L"GetFileVersionInfo");
        goto _cleanup;
    }

    if(!VerQueryValue(m->version_info,
                     L"\\VarFileInfo\\Translation",
                     (LPVOID*) &languages,
                     &c)) {
        rv = KHM_ERROR_INVALID_PARAM;
        _report_mr1(KHERR_WARNING, MSG_RMI_NO_TRANS, _dupstr(m->path));
        _location(L"VerQueryValue");
        goto _cleanup;
    }

    n_languages = (int) (c / sizeof(*languages));

    /* Try searching for the user's default language first */
    lang = GetUserDefaultLangID();
    for (i = 0; i < n_languages; i++) {
        if(languages[i].language == lang)
            break;
    }

    /* If not, try the system default */
    if (i >= n_languages) {
        lang = GetSystemDefaultLangID();
        for (i=0; i<n_languages; i++)
            if (languages[i].language == lang)
                break;
    }

    /* Then try EN_US */
    if (i >= n_languages) {
        lang = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
        for (i=0; i<n_languages; i++)
            if (languages[i].language == lang)
                break;
    }

    /* Language neutral? */
    if (i >= n_languages) {
        lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
        for (i=0; i<n_languages; i++)
            if (languages[i].language == lang)
                break;
    }

    /* Just use the first one? */
    if (i >= n_languages) {
        i = 0;
    }

    if (i >= n_languages) {
        rv = KHM_ERROR_INVALID_PARAM;
        _report_mr0(KHERR_WARNING, MSG_RMI_NO_LOCAL);
        goto _cleanup;
    }

    /* check module name */
    StringCbPrintf(resname, sizeof(resname),
                   L"\\StringFileInfo\\%04x%04x\\" TEXT(NIMV_MODULE),
                   languages[i].language,
                   languages[i].codepage);

    if (!VerQueryValue(m->version_info,
                       resname, (LPVOID *) &r, &c)) {
        rv = KHM_ERROR_INVALID_PARAM;
        _report_mr1(KHERR_WARNING, MSG_RMI_RES_MISSING, 
                    _cstr(TEXT(NIMV_MODULE)));
        goto _cleanup;
    }

    if (c > KMM_MAXCB_NAME ||
        FAILED(StringCbLength(r, KMM_MAXCB_NAME, &cb))) {
        rv = KHM_ERROR_INVALID_PARAM;
        _report_mr1(KHERR_WARNING, MSG_RMI_RES_TOO_LONG,
                    _cstr(TEXT(NIMV_MODULE)));
        goto _cleanup;
    }

    if (wcscmp(r, m->name)) {
        rv = KHM_ERROR_INVALID_PARAM;
        _report_mr2(KHERR_WARNING, MSG_RMI_MOD_MISMATCH,
                    _dupstr(r), _dupstr(m->name));
        goto _cleanup;
    }

    /* check API version */
    StringCbPrintf(resname, sizeof(resname),
                   L"\\StringFileInfo\\%04x%04x\\" TEXT(NIMV_APIVER),
                   languages[i].language,
                   languages[i].codepage);

    if (!VerQueryValue(m->version_info,
                       resname, (LPVOID *) &r, &c)) {
        rv = KHM_ERROR_INVALID_PARAM;
        _report_mr1(KHERR_WARNING, MSG_RMI_RES_MISSING, 
                    _cstr(TEXT(NIMV_APIVER)));
        goto _cleanup;
    }

    if (c > KMM_MAXCB_NAME ||
        FAILED(StringCbLength(r, KMM_MAXCB_NAME, &cb))) {
        rv = KHM_ERROR_INVALID_PARAM;
        _report_mr1(KHERR_WARNING, MSG_RMI_RES_TOO_LONG,
                    _cstr(TEXT(NIMV_APIVER)));
        goto _cleanup;
    }

    t = wcstol(r, NULL, 10);

    rv = kmmint_check_api_version(t);

    if (KHM_FAILED(rv)) {
        _report_mr2(KHERR_WARNING, MSG_RMI_API_MISMATCH,
                    _int32(t), _int32(KH_VERSION_API));
        goto _cleanup;
    }

    /* Looks good.  Now load the description, copyright, support URI
       and file versions */
    if (m->description) {
        PFREE(m->description);
        m->description = NULL;
    }

    StringCbPrintf(resname, sizeof(resname),
                   L"\\StringFileInfo\\%04x%04x\\FileDescription",
                   languages[i].language,
                   languages[i].codepage);

    if (!VerQueryValue(m->version_info,
                       resname, (LPVOID *) &r, &c)) {
        rv = KHM_ERROR_INVALID_PARAM;
        _report_mr1(KHERR_WARNING, MSG_RMI_RES_MISSING, 
                    _cstr(L"FileDescription"));
        goto _cleanup;
    }

    if (c > KMM_MAXCB_DESC ||
        FAILED(StringCbLength(r, KMM_MAXCB_DESC, &cb))) {
        rv = KHM_ERROR_INVALID_PARAM;
        _report_mr1(KHERR_WARNING, MSG_RMI_RES_TOO_LONG,
                    _cstr(L"FileDescription"));
        goto _cleanup;
    }

    cb += sizeof(wchar_t);

    m->description = PMALLOC(cb);
#ifdef DEBUG
    assert(m->description);
#endif
    StringCbCopy(m->description, cb, r);

    /* on to the support URI */
    if (m->support) {
        PFREE(m->support);
        m->support = NULL;
    }

    StringCbPrintf(resname, sizeof(resname),
                   L"\\StringFileInfo\\%04x%04x\\" TEXT(NIMV_SUPPORT),
                   languages[i].language,
                   languages[i].codepage);

    if (!VerQueryValue(m->version_info,
                       resname, (LPVOID *) &r, &c)) {
        rv = KHM_ERROR_INVALID_PARAM;
        _report_mr1(KHERR_WARNING, MSG_RMI_RES_MISSING,
                    _cstr(TEXT(NIMV_SUPPORT)));
        goto _cleanup;
    }

    if (c > KMM_MAXCB_SUPPORT ||
        FAILED(StringCbLength(r, KMM_MAXCB_SUPPORT, &cb))) {
        rv = KHM_ERROR_INVALID_PARAM;
        _report_mr1(KHERR_WARNING, MSG_RMI_RES_TOO_LONG,
                    _cstr(TEXT(NIMV_SUPPORT)));
        goto _cleanup;
    }

    cb += sizeof(wchar_t);

    m->support = PMALLOC(cb);
#ifdef DEBUG
    assert(m->support);
#endif
    StringCbCopy(m->support, cb, r);

    /* the vendor/copyright */
    if (m->vendor) {
        PFREE(m->vendor);
        m->vendor = NULL;
    }

    StringCbPrintf(resname, sizeof(resname),
                   L"\\StringFileInfo\\%04x%04x\\LegalCopyright",
                   languages[i].language,
                   languages[i].codepage);

    if (!VerQueryValue(m->version_info,
                       resname, (LPVOID *) &r, &c)) {
        rv = KHM_ERROR_INVALID_PARAM;
        _report_mr1(KHERR_WARNING, MSG_RMI_RES_MISSING, 
                    _cstr(L"LegalCopyright"));
        goto _cleanup;
    }

    if (c > KMM_MAXCB_SUPPORT ||
        FAILED(StringCbLength(r, KMM_MAXCB_SUPPORT, &cb))) {
        rv = KHM_ERROR_INVALID_PARAM;
        _report_mr1(KHERR_WARNING, MSG_RMI_RES_TOO_LONG,
                    _cstr(L"LegalCopyright"));
        goto _cleanup;
    }

    cb += sizeof(wchar_t);

    m->vendor = PMALLOC(cb);
#ifdef DEBUG
    assert(m->vendor);
#endif
    StringCbCopy(m->vendor, cb, r);

    if (!VerQueryValue(m->version_info,
                       L"\\",
                       (LPVOID *) &vff, &c) ||
        c != sizeof(*vff)) {

        rv = KHM_ERROR_INVALID_PARAM;
        _report_mr1(KHERR_WARNING, MSG_RMI_RES_MISSING, 
                    _cstr(L"Fixed Version Info"));
        goto _cleanup;
    }

    m->file_version.major = HIWORD(vff->dwFileVersionMS);
    m->file_version.minor = LOWORD(vff->dwFileVersionMS);
    m->file_version.patch = HIWORD(vff->dwFileVersionLS);
    m->file_version.aux   = LOWORD(vff->dwFileVersionLS);

    m->prod_version.major = HIWORD(vff->dwProductVersionMS);
    m->prod_version.minor = LOWORD(vff->dwProductVersionMS);
    m->prod_version.patch = HIWORD(vff->dwProductVersionLS);
    m->prod_version.aux   = LOWORD(vff->dwProductVersionLS);

    rv = KHM_ERROR_SUCCESS;

 _cleanup:
    if (KHM_FAILED(rv)) {
        if (m->version_info) {
            PFREE(m->version_info);
            m->version_info = NULL;
        }
    }

    return rv;
}
Пример #2
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();
}
Пример #3
0
/*! \internal
  \brief Manages a plugin message thread.

  Each plugin gets its own plugin thread which is used to dispatch
  messages to the plugin.  This acts as the thread function for the
  plugin thread.*/
DWORD WINAPI kmmint_plugin_broker(LPVOID lpParameter)
{
    DWORD rv = 0;
    kmm_plugin_i * p = (kmm_plugin_i *) lpParameter;

    PDESCTHREAD(p->p.name, L"KMM");

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

    TlsSetValue(tls_kmm, (LPVOID) p);

    kmm_hold_plugin(kmm_handle_from_plugin(p));

    p->tid_thread = GetCurrentThreadId();

    if (IsBadCodePtr(p->p.msg_proc)) {
        _report_mr0(KHERR_WARNING, MSG_PB_INVALID_CODE_PTR);
        rv = KHM_ERROR_INVALID_PARAM;
    } else {
        rv = (*p->p.msg_proc)(KMSG_SYSTEM, KMSG_SYSTEM_INIT, 
                              0, (void *) &(p->p));
        _report_mr1(KHERR_INFO, MSG_PB_INIT_RV, _int32(rv));
    }

    /* if it fails to initialize, we exit the plugin */
    if(KHM_FAILED(rv)) {

        kherr_report(KHERR_ERROR,
                     (wchar_t *) MSG_PB_INIT_FAIL_S,
                     (wchar_t *) KHERR_FACILITY,
                     NULL,
                     (wchar_t *) MSG_PB_INIT_FAIL,
                     (wchar_t *) MSG_PB_INIT_FAIL_G,
                     KHERR_FACILITY_ID,
                     KHERR_SUGGEST_NONE,
                     _cstr(p->p.name),
                     _cstr(p->p.description),
                     _cstr(p->module->path),
                     _cstr(p->module->support),
                     KHERR_RF_MSG_SHORT_DESC |
                     KHERR_RF_MSG_LONG_DESC |
                     KHERR_RF_MSG_SUGGEST
#ifdef _WIN32
                     ,KHERR_HMODULE
#endif
                     );
        _resolve();

        /* exit the plugin first.  Otherwise it may not uninitialize correctly */
        (*p->p.msg_proc)(KMSG_SYSTEM, KMSG_SYSTEM_EXIT, 0, (void *) &(p->p));

        kmmint_remove_from_plugin_queue(p);
        rv = 1;
        _end_task();

        p->state = KMM_PLUGIN_STATE_FAIL_INIT;
        goto _exit;
    }

    /* subscribe to default message classes by plugin type */
    if(p->p.type == KHM_PITYPE_CRED) {
        kmq_subscribe(KMSG_SYSTEM, p->p.msg_proc);
        kmq_subscribe(KMSG_KCDB, p->p.msg_proc);
        kmq_subscribe(KMSG_CRED, p->p.msg_proc);
    } else if(p->p.type == KHM_PITYPE_IDENT) {
        khm_handle h = NULL;

        kmq_subscribe(KMSG_SYSTEM, p->p.msg_proc);
        kmq_subscribe(KMSG_KCDB, p->p.msg_proc);

        kmq_create_subscription(p->p.msg_proc, &h);
        kcdb_identity_set_provider(h);
        /* kcdb deletes the subscription when it's done with it */
    } else if(p->p.type == KHM_PITYPE_CONFIG) {
        /*TODO: subscribe to configuration provider messages here */
    }

    p->state = KMM_PLUGIN_STATE_RUNNING;

    _report_mr0(KHERR_INFO, MSG_PB_INIT_DONE);

    _end_task();

    /* if there were any plugins that were waiting for this one to
       start, we should start them too */
    EnterCriticalSection(&cs_kmm);
    do {
        kmm_plugin_i * pd;
        int i;

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

            pd->n_unresolved--;

            if(pd->n_unresolved == 0) {
                kmmint_add_to_plugin_queue(pd);
                kmm_hold_plugin(kmm_handle_from_plugin(pd));
                kmq_post_message(KMSG_KMM, KMSG_KMM_I_REG, KMM_REG_INIT_PLUGIN, (void *) pd);
            }
        }
    } while(FALSE);
    LeaveCriticalSection(&cs_kmm);

    kmmint_remove_from_plugin_queue(p);

    /* main message loop */
    while(KHM_SUCCEEDED(kmq_dispatch(INFINITE)));

    /* unsubscribe from default message classes by plugin type */
    if(p->p.type == KHM_PITYPE_CRED) {
        kmq_unsubscribe(KMSG_SYSTEM, p->p.msg_proc);
        kmq_unsubscribe(KMSG_KCDB, p->p.msg_proc);
        kmq_unsubscribe(KMSG_CRED, p->p.msg_proc);
    } else if (p->p.type == KHM_PITYPE_IDENT) {
        kmq_unsubscribe(KMSG_KCDB, p->p.msg_proc);
        kmq_unsubscribe(KMSG_SYSTEM, p->p.msg_proc);
        kcdb_identity_set_provider(NULL);
    } else if(p->p.type == KHM_PITYPE_CONFIG) {
        /*TODO: unsubscribe from configuration provider messages here */
    }

    p->p.msg_proc(KMSG_SYSTEM, KMSG_SYSTEM_EXIT, 0, (void *) &(p->p));

 _exit:
    if (p->state >= 0)
        p->state = KMM_PLUGIN_STATE_EXITED;

    /* the following call will automatically release the plugin */
    kmq_post_message(KMSG_KMM, KMSG_KMM_I_REG, 
                     KMM_REG_EXIT_PLUGIN, (void *) p);

    TlsSetValue(tls_kmm, (LPVOID) 0);

    ExitThread(rv);

    /* not reached */
    return rv;
}
Пример #4
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
}
Пример #5
0
khm_int32
krb4_msg_newcred(khm_int32 msg_type, khm_int32 msg_subtype,
                 khm_ui_4 uparam, void * vparam) {

    switch(msg_subtype) {
    case KMSG_CRED_NEW_CREDS:
        {
            khui_new_creds * nc;
            khui_new_creds_by_type * nct;
            khm_size cbsize;
            wchar_t wbuf[256];

            nc = (khui_new_creds *) vparam;

            nct = PMALLOC(sizeof(*nct));
#ifdef DEBUG
            assert(nct);
#endif
            ZeroMemory(nct, sizeof(*nct));

            nct->type = credtype_id_krb4;
            nct->ordinal = 3;
            LoadString(hResModule, IDS_NC_K4_SHORT,
                       wbuf, ARRAYLENGTH(wbuf));
            StringCbLength(wbuf, sizeof(wbuf), &cbsize);
            cbsize += sizeof(wchar_t);

            nct->name = PMALLOC(cbsize);
            StringCbCopy(nct->name, cbsize, wbuf);

            nct->type_deps[nct->n_type_deps++] = credtype_id_krb5;

            nct->h_module = hResModule;
            nct->dlg_proc = k4_nc_dlg_proc;
            nct->dlg_template = MAKEINTRESOURCE(IDD_NC_KRB4);

            khui_cw_add_type(nc, nct);
        }
        break;

    case KMSG_CRED_RENEW_CREDS:
        {
            khui_new_creds * nc;
            khui_new_creds_by_type * nct;
            khm_size cbsize;
            wchar_t wbuf[256];

            nc = (khui_new_creds *) vparam;

            if (!nc->ctx.identity)
                break;

            nct = PMALLOC(sizeof(*nct));
#ifdef DEBUG
            assert(nct);
#endif

            ZeroMemory(nct, sizeof(*nct));

            nct->type = credtype_id_krb4;
            nct->ordinal = 3;
            LoadString(hResModule, IDS_NC_K4_SHORT,
                       wbuf, ARRAYLENGTH(wbuf));
            StringCbLength(wbuf, sizeof(wbuf), &cbsize);
            cbsize += sizeof(wchar_t);

            nct->name = PMALLOC(cbsize);
            StringCbCopy(nct->name, cbsize, wbuf);

            nct->type_deps[nct->n_type_deps++] = credtype_id_krb5;

            khui_cw_add_type(nc, nct);
        }
        break;

    case KMSG_CRED_DIALOG_SETUP:
        break;

    case KMSG_CRED_PROCESS:
        {
            khui_new_creds * nc;
            khui_new_creds_by_type * nct = NULL;
            khm_handle ident = NULL;
            k4_dlg_data * d = NULL;
            long code = 0;
            wchar_t idname[KCDB_IDENT_MAXCCH_NAME];
            khm_size cb;

            nc = (khui_new_creds *) vparam;
            if (KHM_FAILED(khui_cw_find_type(nc, credtype_id_krb4, &nct)))
                break;

            if (nc->subtype == KMSG_CRED_NEW_CREDS ||
                nc->subtype == KMSG_CRED_RENEW_CREDS) {
                khm_int32 method;

                if (nc->subtype == KMSG_CRED_NEW_CREDS) {

                    d = (k4_dlg_data *) nct->aux;
                    if (!d ||
                        nc->n_identities == 0 ||
                        nc->identities[0] == NULL ||
                        nc->result != KHUI_NC_RESULT_PROCESS) {
                        khui_cw_set_response(nc, credtype_id_krb4,
                                             KHUI_NC_RESPONSE_SUCCESS |
                                             KHUI_NC_RESPONSE_EXIT);
                        break;
                    }

                    if (!d->k4_enabled) {
                        k4_write_identity_data(d);
                        khui_cw_set_response(nc, credtype_id_krb4,
                                             KHUI_NC_RESPONSE_SUCCESS |
                                             KHUI_NC_RESPONSE_EXIT);
                        break;
                    }

                    method = d->method;
                    ident = nc->identities[0];

                    cb = sizeof(idname);
                    kcdb_identity_get_name(ident, idname, &cb);
                    _begin_task(0);
                    _report_mr2(KHERR_NONE, MSG_K4_NEW_CREDS,
                                _cstr(ident), _int32(method));
                    _resolve();
                    _describe();

                } else if (nc->subtype == KMSG_CRED_RENEW_CREDS) {

                    if ((nc->ctx.scope == KHUI_SCOPE_IDENT &&
                         nc->ctx.identity != NULL) ||

                        (nc->ctx.scope == KHUI_SCOPE_CREDTYPE &&
                         nc->ctx.cred_type == credtype_id_krb4 &&
                         nc->ctx.identity != NULL) ||

                        (nc->ctx.scope == KHUI_SCOPE_CRED &&
                         nc->ctx.cred_type == credtype_id_krb4 &&
                         nc->ctx.identity != NULL &&
                         nc->ctx.cred != NULL)) {

                        ident = nc->ctx.identity;

                        if (!k4_should_identity_get_k4(ident)) {

                            _reportf(L"Kerberos 4 is not enabled for this identity.  Skipping");

                            khui_cw_set_response(nc, credtype_id_krb4,
                                                 KHUI_NC_RESPONSE_FAILED |
                                                 KHUI_NC_RESPONSE_EXIT);
                            break;
                        }

                    } else {

                        _reportf(L"Kerberos 4 is not within renewal scope. Skipping");

                        khui_cw_set_response(nc, credtype_id_krb4,
                                             KHUI_NC_RESPONSE_FAILED |
                                             KHUI_NC_RESPONSE_EXIT);
                        break;
                    }

                    method = K4_METHOD_K524; /* only k524 is supported
                                                for renewals */

                    _begin_task(0);
                    cb = sizeof(idname);
                    kcdb_identity_get_name(ident, idname, &cb);
                    _report_mr2(KHERR_NONE, MSG_K4_RENEW_CREDS,
                                _cstr(ident), _int32(method));
                    _resolve();
                    _describe();
                } else {
                    assert(FALSE);
                    break;
                }

                if ((method == K4_METHOD_AUTO ||
                     method == K4_METHOD_K524) &&
                    khui_cw_type_succeeded(nc, credtype_id_krb5)) {

                    khm_handle tgt;
                    FILETIME ft_prev;
                    FILETIME ft_new;
                    khm_size cb;

                    _report_mr0(KHERR_INFO, MSG_K4_TRY_K524);

                    tgt = khm_krb4_find_tgt(NULL, ident);
                    if (tgt) {
                        cb = sizeof(ft_prev);
                        if (KHM_FAILED(kcdb_cred_get_attr(tgt,
                                                          KCDB_ATTR_EXPIRE,
                                                          NULL,
                                                          &ft_prev,
                                                          &cb)))
                            ZeroMemory(&ft_prev, sizeof(ft_prev));
                        kcdb_cred_release(tgt);
                    }

                    code = khm_convert524(ident);

                    _reportf(L"khm_convert524 returns code %d", code);

                    if (code == 0) {
                        khui_cw_set_response(nc, credtype_id_krb4,
                                             KHUI_NC_RESPONSE_SUCCESS |
                                             KHUI_NC_RESPONSE_EXIT);

                        if (nc->subtype == KMSG_CRED_NEW_CREDS) {
                            assert(d != NULL);

                            k4_write_identity_data(d);

                        } else if (nc->subtype == KMSG_CRED_RENEW_CREDS &&
                                   (nc->ctx.scope == KHUI_SCOPE_CREDTYPE ||
                                    nc->ctx.scope == KHUI_SCOPE_CRED)) {

                            khm_krb4_list_tickets();

                            tgt = khm_krb4_find_tgt(NULL, ident);

                            if (tgt) {
                                cb = sizeof(ft_new);
                                ZeroMemory(&ft_new, sizeof(ft_new));

                                kcdb_cred_get_attr(tgt,
                                                   KCDB_ATTR_EXPIRE,
                                                   NULL,
                                                   &ft_new,
                                                   &cb);

                                kcdb_cred_release(tgt);
                            }

                            if (!tgt ||
                                CompareFileTime(&ft_new,
                                                &ft_prev) <= 0) {
                                /* The new TGT wasn't much of an
                                   improvement over what we already
                                   had.  We should go out and try to
                                   renew the identity now. */

                                khui_action_context ctx;

                                _reportf(L"Renewal of Krb4 creds failed to get a longer TGT.  Triggering identity renewal");

                                khui_context_create(&ctx,
                                                    KHUI_SCOPE_IDENT,
                                                    nc->ctx.identity,
                                                    KCDB_CREDTYPE_INVALID,
                                                    NULL);
                                khui_action_trigger(KHUI_ACTION_RENEW_CRED,
                                                    &ctx);

                                khui_context_release(&ctx);
                            }
                        }

                        _end_task();
                        break;

                    } else if (method == K4_METHOD_K524) {
                        khui_cw_set_response(nc, credtype_id_krb4,
                                             KHUI_NC_RESPONSE_FAILED |
                                             KHUI_NC_RESPONSE_EXIT);

			if (nc->subtype == KMSG_CRED_RENEW_CREDS &&
			    (nc->ctx.scope == KHUI_SCOPE_CREDTYPE ||
			     nc->ctx.scope == KHUI_SCOPE_CRED)) {
			    /* We were trying to get a new Krb4 TGT
			       for this identity.  Sometimes this
			       fails because of restrictions placed on
			       K524d regarding the lifetime of the
			       issued K4 TGT.  In this case, we
			       trigger a renewal of the identity in
			       the hope that the new K5 TGT will allow
			       us to successfully get a new K4 TGT
			       next time over using the new K5 TGT. */

			    khui_action_context ctx;

                            _reportf(L"Renewal of Krb4 creds failed using k524.  Triggerring identity renewal.");

			    khui_context_create(&ctx,
						KHUI_SCOPE_IDENT,
						nc->ctx.identity,
						KCDB_CREDTYPE_INVALID,
						NULL);

			    khui_action_trigger(KHUI_ACTION_RENEW_CRED,
						&ctx);

			    khui_context_release(&ctx);
			}

                        _end_task();
                        break;

                    }
                }

                /* only supported for new credentials */
                if (method == K4_METHOD_AUTO ||
                    method == K4_METHOD_PASSWORD) {

                    khm_size n_prompts = 0;
                    khm_size idx;
                    khm_size cb;
                    wchar_t wpwd[KHUI_MAXCCH_PROMPT_VALUE];
                    char pwd[KHUI_MAXCCH_PROMPT_VALUE];
                    wchar_t widname[KCDB_IDENT_MAXCCH_NAME];
                    char idname[KCDB_IDENT_MAXCCH_NAME];

                    char * aname = NULL;
                    char * inst = NULL;
                    char * realm = NULL;

                    assert(nc->subtype == KMSG_CRED_NEW_CREDS);

                    _report_mr0(KHERR_INFO, MSG_K4_TRY_PASSWORD);

                    code = TRUE; /* just has to be non-zero */

                    khui_cw_get_prompt_count(nc, &n_prompts);

                    if (n_prompts == 0)
                        goto _skip_pwd;

                    for (idx = 0; idx < n_prompts; idx++) {
                        khui_new_creds_prompt * p;

                        if (KHM_FAILED(khui_cw_get_prompt(nc, idx, &p)))
                            continue;

                        if (p->type == KHUI_NCPROMPT_TYPE_PASSWORD)
                            break;
                    }

                    if (idx >= n_prompts) {
                        _reportf(L"Password prompt not found");
                        goto _skip_pwd;
                    }

                    khui_cw_sync_prompt_values(nc);

                    cb = sizeof(wpwd);
                    if (KHM_FAILED(khui_cw_get_prompt_value(nc, idx,
                                                            wpwd,
                                                            &cb))) {
                        _reportf(L"Failed to obtain password value");
                        goto _skip_pwd;
                    }

                    UnicodeStrToAnsi(pwd, sizeof(pwd), wpwd);

                    cb = sizeof(widname);
                    kcdb_identity_get_name(ident,
                                           widname,
                                           &cb);

                    UnicodeStrToAnsi(idname, sizeof(idname), widname);

                    {
                        char * atsign;

                        atsign = strchr(idname, '@');
                        if (atsign == NULL) {
                            _reportf(L"Identity name does not contain an '@'");
                            goto _skip_pwd;
                        }

                        *atsign++ = 0;

                        realm = atsign;
                    }

                    {
                        char * slash;

                        slash = strchr(idname, '/');
                        if (slash != NULL) {
                            *slash++ = 0;
                            inst = slash;
                        } else {
                            inst = "";
                        }
                    }

                    aname = idname;

                    code = khm_krb4_kinit(aname, inst, realm,
                                          (long) d->lifetime, pwd);

                    _reportf(L"khm_krb4_kinit returns code %d", code);

                _skip_pwd:

                    if (code) {
                        khui_cw_set_response(nc, credtype_id_krb4,
                                             KHUI_NC_RESPONSE_EXIT |
                                             KHUI_NC_RESPONSE_FAILED);

                    } else {
                        khui_cw_set_response(nc, credtype_id_krb4,
                                             KHUI_NC_RESPONSE_EXIT |
                                             KHUI_NC_RESPONSE_SUCCESS);

                        if (nc->subtype == KMSG_CRED_NEW_CREDS) {

                            assert(d != NULL);
                            k4_write_identity_data(d);

                        }
                    }
                }

                _end_task();
            }
        }
        break;

    case KMSG_CRED_END:
        {
            khui_new_creds * nc;
            khui_new_creds_by_type * nct = NULL;

            nc = (khui_new_creds *) vparam;
            if (KHM_FAILED(khui_cw_find_type(nc, credtype_id_krb4, &nct)))
                break;

            khui_cw_del_type(nc, credtype_id_krb4);

            if (nct->name)
                PFREE(nct->name);

            if (nct->credtext)
                PFREE(nct->credtext);

            PFREE(nct);
        }
        break;
    }

    return KHM_ERROR_SUCCESS;
}