Exemple #1
0
khm_int32 KHMAPI
addr_list_toString(const void *d, khm_size cb_d,
		   wchar_t *buf, khm_size *pcb_buf,
		   khm_int32 flags)
{
    HostAddresses as;
    size_t len;
    size_t i;

    wchar_t wstr[2048] = L"";
    wchar_t *wstr_d = &wstr[0];
    khm_size cch_wstr = ARRAYLENGTH(wstr);

    if ( decode_HostAddresses((const unsigned char *) d, cb_d, &as, &len) ) {
	assert(FALSE);
	return KHM_ERROR_INVALID_PARAM;
    }

    for (i=0; i < as.len; i++) {
	char buf[1024];
	wchar_t wbuf[1024];

	len = sizeof(buf);
	if (krb5_print_address(&as.val[i], buf, sizeof(buf), &len)) {
	    assert(FALSE);
	    continue;
	}

	AnsiStrToUnicode(wbuf, sizeof(wbuf), buf);
	if (FAILED(StringCchCatEx(wstr_d, cch_wstr, wbuf, &wstr_d, &cch_wstr,
				  STRSAFE_NO_TRUNCATION))) {
	    assert(FALSE);
	    continue;
	}

	if (i + 1 < as.len) {
	    if (FAILED(StringCchCatEx(wstr_d, cch_wstr, L",", &wstr_d, &cch_wstr,
				      STRSAFE_NO_TRUNCATION))) {
		assert(FALSE);
		continue;
	    }
	}
    }

    len = (ARRAYLENGTH(wstr) - cch_wstr) * sizeof(wchar_t);

    if (buf == NULL || *pcb_buf < len) {
	*pcb_buf = len;
	return KHM_ERROR_TOO_LONG;
    }

    StringCbCopy(buf, *pcb_buf, wstr);
    *pcb_buf = len;
    free_HostAddresses(&as);

    return KHM_ERROR_SUCCESS;
}
INT_PTR CALLBACK
krb4_confg_proc(HWND hwnd,
                UINT uMsg,
                WPARAM wParam,
                LPARAM lParam) {

    static BOOL in_init = FALSE;
    k4_config_dlg_data * d;

    switch(uMsg) {
    case WM_INITDIALOG:
        {
            wchar_t wbuf[MAX_PATH];
            CHAR krb_path[MAX_PATH];
            CHAR krbrealm_path[MAX_PATH];
            CHAR ticketName[MAX_PATH];
            char * pticketName;
            size_t krb_path_sz = sizeof(krb_path);
            size_t krbrealm_path_sz = sizeof(krbrealm_path);
            khm_size cbsize;

            d = PMALLOC(sizeof(*d));
            ZeroMemory(d, sizeof(*d));

#pragma warning(push)
#pragma warning(disable: 4244)
            SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) d);
#pragma warning(pop)

            d->node = (khui_config_node) lParam;

            in_init = TRUE;

            // Set KRB.CON
            memset(krb_path, '\0', sizeof(krb_path));
            if (!pkrb_get_krbconf2(krb_path, &krb_path_sz)) {
                // Error has happened
            } else { // normal find
                AnsiStrToUnicode(wbuf, sizeof(wbuf), krb_path);
                SetDlgItemText(hwnd, IDC_CFG_CFGPATH, wbuf);
                StringCbCopyA(d->krb_path, sizeof(d->krb_path), krb_path);
            }

            // Set KRBREALM.CON
            memset(krbrealm_path, '\0', sizeof(krbrealm_path));
            if (!pkrb_get_krbrealm2(krbrealm_path, &krbrealm_path_sz)) {
                // Error has happened
            } else {
                AnsiStrToUnicode(wbuf, sizeof(wbuf), krbrealm_path);
                SetDlgItemText(hwnd, IDC_CFG_RLMPATH, wbuf);
                StringCbCopyA(d->krbrealm_path, sizeof(d->krbrealm_path),
                              krbrealm_path);
            }

            cbsize = sizeof(wbuf);
            if (KHM_SUCCEEDED(khc_read_string(csp_params, L"TktString",
                                              wbuf, &cbsize)) &&
                wbuf[0] != L'\0') {

                UnicodeStrToAnsi(ticketName, sizeof(ticketName), wbuf);

            } else {

                // Set TICKET.KRB file Editbox
                *ticketName = 0;
                pkrb_set_tkt_string(0);

                pticketName = ptkt_string();
                if (pticketName)
                    StringCbCopyA(ticketName, sizeof(ticketName), pticketName);

            }
	
            if (!*ticketName) {
                // error
            } else {
                AnsiStrToUnicode(wbuf, sizeof(wbuf), ticketName);
                SetDlgItemText(hwnd, IDC_CFG_CACHE, wbuf);
                StringCbCopyA(d->tkt_string, sizeof(d->tkt_string),
                              ticketName);
            }

            in_init = FALSE;

        }
        break;

    case WM_COMMAND:
        if (MAKEWPARAM(IDC_CFG_CACHE, EN_CHANGE)) {
            char tkt_string[MAX_PATH];
            wchar_t wtkt_string[MAX_PATH];

            if (in_init) {
                return TRUE;
            }

            d = (k4_config_dlg_data *) (LONG_PTR)
                GetWindowLongPtr(hwnd, DWLP_USER);

            if (d == NULL)
                return TRUE;

            tkt_string[0] = 0;
            wtkt_string[0] = 0;

            GetDlgItemText(hwnd, IDC_CFG_CACHE,
                           wtkt_string, ARRAYLENGTH(wtkt_string));
            UnicodeStrToAnsi(tkt_string, sizeof(tkt_string),
                             wtkt_string);

            if (_stricmp(tkt_string, d->tkt_string)) {
                khui_cfg_set_flags(d->node,
                                   KHUI_CNFLAG_MODIFIED,
                                   KHUI_CNFLAG_MODIFIED);
            } else {
                khui_cfg_set_flags(d->node,
                                   0,
                                   KHUI_CNFLAG_MODIFIED);
            }

            return TRUE;
        }
        break;

    case KHUI_WM_CFG_NOTIFY:
        if (HIWORD(wParam) == WMCFG_APPLY) {
            wchar_t wtkt_string[MAX_PATH];
            char tkt_string[MAX_PATH];
            int t;

            d = (k4_config_dlg_data *) (LONG_PTR)
                GetWindowLongPtr(hwnd, DWLP_USER);

            if (d == NULL)
                return TRUE;

            t = GetDlgItemText(hwnd, IDC_CFG_CACHE,
                               wtkt_string, ARRAYLENGTH(wtkt_string));
            if (t == 0)
                return TRUE;

            UnicodeStrToAnsi(tkt_string, sizeof(tkt_string), wtkt_string);

            if (_stricmp(tkt_string, d->tkt_string)) {

                pkrb_set_tkt_string(tkt_string);

                khc_write_string(csp_params, L"TktString", wtkt_string);

                khui_cfg_set_flags(d->node,
                                   KHUI_CNFLAG_APPLIED,
                                   KHUI_CNFLAG_APPLIED |
                                   KHUI_CNFLAG_MODIFIED);
                khm_krb4_list_tickets();
            } else {
                khui_cfg_set_flags(d->node,
                                   0,
                                   KHUI_CNFLAG_MODIFIED);
            }

            return TRUE;
        }
        break;

    case WM_DESTROY:
        d = (k4_config_dlg_data *) (LONG_PTR)
            GetWindowLongPtr(hwnd, DWLP_USER);

        if (d) {
            PFREE(d);
            SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) 0);
        }

        break;
    }
    return FALSE;
}
Exemple #3
0
khm_int32 KHMAPI
khm_krb5_find_ccache_for_identity(khm_handle ident, krb5_context *pctx,
                                  void * buffer, khm_size * pcbbuf)
{
    krb5_context        ctx = 0;
    krb5_ccache         cache = 0;
    krb5_error_code     code;
    apiCB *             cc_ctx = 0;
    struct _infoNC **   pNCi = NULL;
    int                 i;
    khm_int32           t;
    wchar_t *           ms = NULL;
    khm_size            cb;
    krb5_timestamp      expiration = 0;
    krb5_timestamp      best_match_expiration = 0;
    char                best_match_ccname[256] = "";
    khm_handle          csp_params = NULL;
    khm_handle          csp_plugins = NULL;

    if (!buffer || !pcbbuf)
    return KHM_ERROR_GENERAL;

    ctx = *pctx;

    if (!pcc_initialize ||
        !pcc_get_NC_info ||
        !pcc_free_NC_info ||
        !pcc_shutdown)
        goto _skip_cc_iter;

    code = pcc_initialize(&cc_ctx, CC_API_VER_2, NULL, NULL);
    if (code)
        goto _exit;

    code = pcc_get_NC_info(cc_ctx, &pNCi);

    if (code) 
        goto _exit;

    for(i=0; pNCi[i]; i++) {
        if (pNCi[i]->vers != CC_CRED_V5)
            continue;

        code = (*pkrb5_cc_resolve)(ctx, pNCi[i]->name, &cache);
        if (code)
            continue;

        /* need a function to check the cache for the identity
         * and determine if it has valid tickets.  If it has 
         * the right identity and valid tickets, store the 
         * expiration time and the cache name.  If it has the
         * right identity but no valid tickets, store the ccache
         * name and an expiration time of zero.  if it does not
         * have the right identity don't save the name.
         * 
         * Keep searching to find the best cache available.
         */

        if (KHM_SUCCEEDED(khm_get_identity_expiration_time(ctx, cache, 
                                                           ident, 
                                                           &expiration))) {
            if ( expiration > best_match_expiration ) {
                best_match_expiration = expiration;
                StringCbCopyA(best_match_ccname, 
                              sizeof(best_match_ccname),
                              "API:");
                StringCbCatA(best_match_ccname,
                             sizeof(best_match_ccname),
                             pNCi[i]->name);
                expiration = 0;
            }
        }

        if(ctx != NULL && cache != NULL)
            (*pkrb5_cc_close)(ctx, cache);
        cache = 0;
    }

 _skip_cc_iter:

    if (KHM_SUCCEEDED(kmm_get_plugins_config(0, &csp_plugins))) {
        khc_open_space(csp_plugins, L"Krb5Cred\\Parameters",  0, &csp_params);
        khc_close_space(csp_plugins);
        csp_plugins = NULL;
    }

#ifdef DEBUG
    if (csp_params == NULL) {
        assert(FALSE);
    }
#endif

    if (csp_params &&
        KHM_SUCCEEDED(khc_read_int32(csp_params, L"MsLsaList", &t)) && t) {
        code = (*pkrb5_cc_resolve)(ctx, "MSLSA:", &cache);
        if (code == 0 && cache) {
            if (KHM_SUCCEEDED(khm_get_identity_expiration_time(ctx, cache, 
                                                               ident, 
                                                               &expiration))) {
                if ( expiration > best_match_expiration ) {
                    best_match_expiration = expiration;
                    StringCbCopyA(best_match_ccname, sizeof(best_match_ccname),
                                  "MSLSA:");
                    expiration = 0;
                }
            }
        }

        if (ctx != NULL && cache != NULL)
            (*pkrb5_cc_close)(ctx, cache);

        cache = 0;
    }

    if (csp_params &&
        khc_read_multi_string(csp_params, L"FileCCList", NULL, &cb)
        == KHM_ERROR_TOO_LONG &&
        cb > sizeof(wchar_t) * 2) {

        wchar_t * t;
        char ccname[MAX_PATH + 6];

        ms = PMALLOC(cb);

#ifdef DEBUG
        assert(ms);
#endif

        khc_read_multi_string(csp_params, L"FileCCList", ms, &cb);
        for(t = ms; t && *t; t = multi_string_next(t)) {
            StringCchPrintfA(ccname, ARRAYLENGTH(ccname),
                             "FILE:%S", t);

            code = (*pkrb5_cc_resolve)(ctx, ccname, &cache);
            if (code)
                continue;

            if (KHM_SUCCEEDED(khm_get_identity_expiration_time(ctx, cache, 
                                                               ident, 
                                                               &expiration))) {
                if ( expiration > best_match_expiration ) {
                    best_match_expiration = expiration;
                    StringCbCopyA(best_match_ccname,
                                  sizeof(best_match_ccname),
                                  ccname);
                    expiration = 0;
                }
            }

            if (ctx != NULL && cache != NULL)
                (*pkrb5_cc_close)(ctx, cache);
            cache = 0;
        }

        PFREE(ms);
    }
 _exit:
    if (csp_params)
        khc_close_space(csp_params);

    if (pNCi)
        (*pcc_free_NC_info)(cc_ctx, &pNCi);

    if (cc_ctx)
        (*pcc_shutdown)(&cc_ctx);

    if (best_match_ccname[0]) {
        
        if (*pcbbuf = AnsiStrToUnicode((wchar_t *)buffer, 
                                       *pcbbuf,
                                       best_match_ccname)) {

            *pcbbuf = (*pcbbuf + 1) * sizeof(wchar_t);

            return KHM_ERROR_SUCCESS;
        }

    }

    return KHM_ERROR_GENERAL;
}
static krb5_error_code KRB5_CALLCONV
kinit_prompter(krb5_context context,
               void *data,
               const char *name,
               const char *banner,
               int num_prompts,
               krb5_prompt prompts[])
{
    int i;
    k5_kinit_task * kt;
    khm_size ncp;
    krb5_error_code code = 0;
    BOOL new_prompts = TRUE;
    khm_handle csp_prcache = NULL;

    kt = (k5_kinit_task *) data;
    assert(kt && kt->magic == K5_KINIT_TASK_MAGIC);

    EnterCriticalSection(&kt->cs);

    if (kt->state == K5_KINIT_STATE_ABORTED) {
        LeaveCriticalSection(&kt->cs);
        return KRB5_LIBOS_PWDINTR;
    }

#ifdef DEBUG
    assert(kt->state == K5_KINIT_STATE_INCALL ||
           kt->state == K5_KINIT_STATE_CONFIRM);

    _reportf(L"k5_kinit_prompter() received %d prompts with name=[%S] banner=[%S]",
             num_prompts,
             name, banner);
    for (i=0; i < num_prompts; i++) {
        _reportf(L"Prompt[%d]: string[%S]", i, prompts[i].prompt);
    }
#endif

    /* we got prompts?  Then we assume that the principal is valid */

    if (!kt->is_valid_principal) {
        kt->is_valid_principal = TRUE;

        /* if the flags that were used to call kinit were restricted
           because we didn't know the validity of the principal, then
           we need to go back and retry the call with the correct
           flags. */
        if (kt->params.forwardable ||
            kt->params.proxiable ||
            kt->params.renewable) {

            _reportf(L"Retrying kinit call due to restricted flags on first call.");
            kt->state = K5_KINIT_STATE_RETRY;
            LeaveCriticalSection(&kt->cs);

            return KRB5_LIBOS_PWDINTR;
        }
    }

    /* check if we are already showing the right prompts */
    khui_cw_get_prompt_count(kt->nc, &ncp);

    if (num_prompts != (int) ncp && num_prompts != 0)
        goto _show_new_prompts;

    for (i=0; i < num_prompts; i++) {
        wchar_t wprompt[KHUI_MAXCCH_PROMPT];
        khui_new_creds_prompt * p;

        if(prompts[i].prompt) {
            AnsiStrToUnicode(wprompt, sizeof(wprompt),
                             prompts[i].prompt);
        } else {
            wprompt[0] = L'\0';
        }

        if (KHM_FAILED(khui_cw_get_prompt(kt->nc, i, &p)))
            break;

        if (                    /* if we received a prompt string,
                                   then it should be the same as the
                                   one that is displayed */
            (wprompt[0] != L'\0' &&
             (p->prompt == NULL ||
              wcscmp(wprompt, p->prompt))) ||

                                /* if we didn't receive one, then
                                   there shouldn't be one displayed.
                                   This case really shouldn't happen
                                   in reality, but we check anyway. */
            (wprompt[0] == L'\0' &&
             p->prompt != NULL) ||

                                /* the type should match */
            (prompts[i].type != p->type) ||

                                /* if this prompt should be hidden,
                                   then it must also be so */
            (prompts[i].hidden &&
             !(p->flags & KHUI_NCPROMPT_FLAG_HIDDEN)) ||
            (!prompts[i].hidden &&
             (p->flags & KHUI_NCPROMPT_FLAG_HIDDEN))
            )

            break;
    }

    if (i >= num_prompts) {

        new_prompts = FALSE;

        /* ok. looks like we are already showing the same set of
           prompts that we were supposed to show.  Sync up the values
           and go ahead. */
        goto _process_prompts;
    }

 _show_new_prompts:
    if (num_prompts == 0) {

        assert(FALSE);

        khui_cw_notify_identity_state(kt->nc,
                                      kt->nct->hwnd_panel,
                                      NULL,
                                      KHUI_CWNIS_READY |
                                      KHUI_CWNIS_NOPROGRESS |
                                      KHUI_CWNIS_VALIDATED, 0);

        code = 0;
        kt->is_null_password = TRUE;
        goto _process_prompts;
    }

    /* in addition to showing new prompts, we also cache the first set
       of prompts. */
    if (kt->prompt_set_index == 0) {
        khm_handle csp_idconfig = NULL;
        khm_handle csp_idk5 = NULL;

        kcdb_identity_get_config(kt->identity,
                                 KHM_FLAG_CREATE,
                                 &csp_idconfig);

        if (csp_idconfig != NULL)
            khc_open_space(csp_idconfig,
                           CSNAME_KRB5CRED,
                           KHM_FLAG_CREATE,
                           &csp_idk5);

        if (csp_idk5 != NULL)
            khc_open_space(csp_idk5,
                           CSNAME_PROMPTCACHE,
                           KHM_FLAG_CREATE,
                           &csp_prcache);

        khc_close_space(csp_idconfig);
        khc_close_space(csp_idk5);
    }

    {
        wchar_t wbanner[KHUI_MAXCCH_BANNER];
        wchar_t wname[KHUI_MAXCCH_PNAME];

        if(banner)
            AnsiStrToUnicode(wbanner, sizeof(wbanner), banner);
        else
            wbanner[0] = L'\0';

        if(name)
            AnsiStrToUnicode(wname, sizeof(wname), name);
        else
            LoadString(hResModule, IDS_PNAME_PW, wname, ARRAYLENGTH(wname));

        khui_cw_clear_prompts(kt->nc);

        khui_cw_begin_custom_prompts(kt->nc, num_prompts, wbanner, wname);

        if (csp_prcache) {
            FILETIME current;
            FILETIME lifetime;
            FILETIME expiry;
            khm_int64 iexpiry;
            khm_int32 t = 0;

            khc_write_string(csp_prcache, L"Banner", wbanner);
            khc_write_string(csp_prcache, L"Name", (name)? wname: L"");
            khc_write_int32(csp_prcache, L"PromptCount", (khm_int32) num_prompts);

            GetSystemTimeAsFileTime(&current);
#ifdef USE_PROMPT_CACHE_LIFETIME
            khc_read_int32(csp_params, L"PromptCacheLifetime", &t);
            if (t == 0)
                t = 172800;         /* 48 hours */
#else
            khc_read_int32(csp_params, L"MaxRenewLifetime", &t);
            if (t == 0)
                t = 2592000;    /* 30 days */
            t += 604800;        /* + 7 days */
#endif
            TimetToFileTimeInterval(t, &lifetime);
            expiry = FtAdd(&current, &lifetime);
            iexpiry = FtToInt(&expiry);

            khc_write_int64(csp_prcache, L"ExpiresOn", iexpiry);
        }
    }

    for(i=0; i < num_prompts; i++) {
        wchar_t wprompt[KHUI_MAXCCH_PROMPT];

        if(prompts[i].prompt) {
            AnsiStrToUnicode(wprompt, sizeof(wprompt),
                             prompts[i].prompt);
        } else {
            wprompt[0] = 0;
        }

        khui_cw_add_prompt(kt->nc, prompts[i].type,
                           wprompt, NULL,
                           (prompts[i].hidden?KHUI_NCPROMPT_FLAG_HIDDEN:0));

        if (csp_prcache) {
            khm_handle csp_p = NULL;
            wchar_t wnum[8];    /* should be enough for 10
                                   million prompts */

            wnum[0] = 0;
            StringCbPrintf(wnum, sizeof(wnum), L"%d", i);

            khc_open_space(csp_prcache, wnum, KHM_FLAG_CREATE, &csp_p);

            if (csp_p) {
                khc_write_string(csp_p, L"Prompt", wprompt);
                khc_write_int32(csp_p, L"Type", prompts[i].type);
                khc_write_int32(csp_p, L"Flags",
                                (prompts[i].hidden?
                                 KHUI_NCPROMPT_FLAG_HIDDEN:0));

                khc_close_space(csp_p);
            }
        }
    }

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

 _process_prompts:
    if (new_prompts) {
        kt->state = K5_KINIT_STATE_WAIT;

        kcdb_identity_set_flags(kt->identity,
                                KCDB_IDENT_FLAG_VALID | KCDB_IDENT_FLAG_KEY_EXPORT,
                                KCDB_IDENT_FLAG_VALID | KCDB_IDENT_FLAG_KEY_EXPORT);
        khui_cw_notify_identity_state(kt->nc, kt->nct->hwnd_panel, L"",
                                      KHUI_CWNIS_VALIDATED |
                                      KHUI_CWNIS_READY, 0);

        SetEvent(kt->h_parent_wait);
        LeaveCriticalSection(&kt->cs);
        WaitForSingleObject(kt->h_task_wait, INFINITE);
        EnterCriticalSection(&kt->cs);
    }

    /* we get here after the user selects an action that either
       cancels the credentials acquisition operation or triggers the
       actual acquisition of credentials. */
    if (kt->state != K5_KINIT_STATE_INCALL &&
        kt->state != K5_KINIT_STATE_CONFIRM) {
        code = KRB5_LIBOS_PWDINTR;
        goto _exit;
    }

    kt->is_null_password = FALSE;

    /* otherwise, we need to get the data back from the UI and return
       0 */

    khui_cw_sync_prompt_values(kt->nc);

    for(i=0; i<num_prompts; i++) {
        krb5_data * d;
        wchar_t wbuf[512];
        khm_size cbbuf;
        size_t cch;

        d = prompts[i].reply;

        cbbuf = sizeof(wbuf);
        if(KHM_SUCCEEDED(khui_cw_get_prompt_value(kt->nc, i, wbuf, &cbbuf))) {
            UnicodeStrToAnsi(d->data, d->length, wbuf);
            if(SUCCEEDED(StringCchLengthA(d->data, d->length, &cch)))
                d->length = (unsigned int) cch;
            else
                d->length = 0;
        } else {
            assert(FALSE);
            d->length = 0;
        }

        if (prompts[i].type == KRB5_PROMPT_TYPE_PASSWORD &&
            d->length == 0)

            kt->is_null_password = TRUE;
    }

    if (khui_cw_get_persist_private_data(kt->nc) &&
        num_prompts == 1 &&
	prompts[0].type == KRB5_PROMPT_TYPE_PASSWORD &&
        prompts[0].reply->length != 0) {
        k5_reply_to_acqpriv_id_request(kt->nc, prompts[0].reply);
    }

 _exit:

    kt->prompt_set_index++;

    LeaveCriticalSection(&kt->cs);

    /* entering a NULL password is equivalent to cancelling out */
    if (kt->is_null_password)
        return KRB5_LIBOS_PWDINTR;
    else
        return code;
}
Exemple #5
0
void khm_err_describe(long code, wchar_t * buf, khm_size cbbuf,
                      DWORD * suggestion,
                      kherr_suggestion * suggest_code)
{
    const char * com_err_msg;
    int offset;
    long table_num;
    DWORD msg_id = 0;
    DWORD sugg_id = 0;
    kherr_suggestion sugg_code = KHERR_SUGGEST_NONE;

    if (suggestion == NULL || buf == NULL || cbbuf == 0 || suggest_code == 0)
        return;

    *buf = L'\0';

    offset = (int) (code & 255);
    table_num = code - offset;
    com_err_msg = perror_message(code);

    *suggestion = 0;
    *suggest_code = KHERR_SUGGEST_NONE;

    if (WSABASEERR <= code && code < (WSABASEERR + 1064)) {
        /* winsock error */
        table_num = WSABASEERR;
        offset = code - WSABASEERR;
    }

    switch(table_num)
    {
    case krb_err_base:
    case kadm_err_base:
    case WSABASEERR:
	break;
    default:

        if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY) {
            *suggestion = MSG_ERR_S_INTEGRITY;
        }
        *suggest_code = KHERR_SUGGEST_RETRY;
        AnsiStrToUnicode(buf, cbbuf, com_err_msg);
	return;
    }

    if (table_num == krb_err_base) {
        switch(offset) {
        case KDC_NAME_EXP:           /* 001 Principal expired */
        case KDC_SERVICE_EXP:        /* 002 Service expired */
        case KDC_AUTH_EXP:           /* 003 Auth expired */
        case KDC_PKT_VER:            /* 004 Protocol version unknown */
        case KDC_P_MKEY_VER:         /* 005 Wrong master key version */
        case KDC_S_MKEY_VER:         /* 006 Wrong master key version */
        case KDC_BYTE_ORDER:         /* 007 Byte order unknown */
        case KDC_PR_N_UNIQUE:        /* 009 Principal not unique */
        case KDC_NULL_KEY:           /* 010 Principal has null key */
        case KDC_GEN_ERR:            /* 011 Generic error from KDC */
        case INTK_W_NOTALL   :       /* 061 Not ALL tickets returned */
        case INTK_PROT       :       /* 063 Protocol Error */
        case INTK_ERR        :       /* 070 Other error */
            msg_id = MSG_ERR_UNKNOWN;
            sugg_code = KHERR_SUGGEST_RETRY;
            break;

        case KDC_PR_UNKNOWN:         /* 008 Principal unknown */
            msg_id = MSG_ERR_PR_UNKNOWN;
            sugg_code = KHERR_SUGGEST_RETRY;
            break;
        case GC_TKFIL                : /* 021 Can't read ticket file */
        case GC_NOTKT                : /* 022 Can't find ticket or TGT */
            msg_id = MSG_ERR_TKFIL;
            sugg_id = MSG_ERR_S_TKFIL;
            sugg_code = KHERR_SUGGEST_RETRY;
            break;
        case MK_AP_TGTEXP    :  /* 026 TGT Expired */
            /* no extra error msg */
            break;

        case RD_AP_TIME              : /* 037 delta_t too big */
            msg_id = MSG_ERR_CLOCKSKEW;
            sugg_id = MSG_ERR_S_CLOCKSKEW;
            sugg_code = KHERR_SUGGEST_RETRY;
            break;

        case RD_AP_UNDEC             : /* 031 Can't decode
                                          authenticator */
        case RD_AP_EXP               : /* 032 Ticket expired */
        case RD_AP_NYV               : /* 033 Ticket not yet valid */
        case RD_AP_REPEAT    :  /* 034 Repeated request */
        case RD_AP_NOT_US    :  /* 035 The ticket isn't for us */
        case RD_AP_INCON             : /* 036 Request is inconsistent */
        case RD_AP_BADD              : /* 038 Incorrect net address */
        case RD_AP_VERSION   :  /* 039 protocol version mismatch */
        case RD_AP_MSG_TYPE  :  /* 040 invalid msg type */
        case RD_AP_MODIFIED  :  /* 041 message stream modified */
        case RD_AP_ORDER             : /* 042 message out of order */
        case RD_AP_UNAUTHOR  :  /* 043 unauthorized request */
            /* no extra error msg */
            sugg_code = KHERR_SUGGEST_RETRY;
            break;

        case GT_PW_NULL:     /* 51    Current PW is null */
        case GT_PW_BADPW:    /* 52    Incorrect current password */
        case GT_PW_PROT:     /* 53    Protocol Error */
        case GT_PW_KDCERR:   /* 54    Error returned by KDC */
        case GT_PW_NULLTKT:  /* 55    Null tkt returned by KDC */
            /* no error msg yet */
            sugg_code = KHERR_SUGGEST_RETRY;
            break;

            /* Values returned by send_to_kdc */
        case SKDC_RETRY   :     /* 56    Retry count exceeded */
        case SKDC_CANT    :     /* 57    Can't send request */
            msg_id = MSG_ERR_KDC_CONTACT;
            break;
            /* no error message on purpose: */
        case INTK_BADPW      :  /* 062 Incorrect password */
            sugg_code = KHERR_SUGGEST_RETRY;
            break;
        default:
            /* no extra error msg */
            break;
        }
    } else if (table_num == kadm_err_base) {
        switch(code) {
        case KADM_INSECURE_PW:
            /* if( kadm_info != NULL ){
             * wsprintf(buf, "%s\n%s", com_err_msg, kadm_info);
             * } else {
             * wsprintf(buf, "%s\nPlease see the help file for information "
             * "about secure passwords.", com_err_msg);
             * }
             * com_err_msg = buf;
             */

            /* The above code would be preferred since it allows site
             * specific information to be delivered from the Kerberos
             * server. However the message box is too small for VGA
             * screens.  It does work well if we only have to support
             * 1024x768
             */

            msg_id = MSG_ERR_INSECURE_PW;
            sugg_code = KHERR_SUGGEST_RETRY;
            break;

        default:
            /* no extra error msg */
            break;
        }
    } else if (table_num == WSABASEERR) {
        switch(code) {
        case WSAENETDOWN:
            msg_id = MSG_ERR_NETDOWN;
            sugg_id = MSG_ERR_S_NETRETRY;
            sugg_code = KHERR_SUGGEST_RETRY;
            break;

        case WSATRY_AGAIN:
            msg_id = MSG_ERR_TEMPDOWN;
            sugg_id = MSG_ERR_S_TEMPDOWN;
            sugg_code = KHERR_SUGGEST_RETRY;
            break;

        case WSAENETUNREACH:
        case WSAENETRESET:
        case WSAECONNABORTED:
        case WSAECONNRESET:
        case WSAETIMEDOUT:
        case WSAECONNREFUSED:
        case WSAEHOSTDOWN:
        case WSAEHOSTUNREACH:
            msg_id = MSG_ERR_NOHOST;
            sugg_id = MSG_ERR_S_NOHOST;
            sugg_code = KHERR_SUGGEST_RETRY;
            break;
        }
    }

    if (msg_id != 0) {
        FormatMessage(FORMAT_MESSAGE_FROM_HMODULE |
                      FORMAT_MESSAGE_IGNORE_INSERTS,
                      KHERR_HMODULE,
                      msg_id,
                      0,
                      buf,
                      (int) (cbbuf / sizeof(buf[0])),
                      NULL);
    }

    if (sugg_id != 0) {
        *suggestion = sugg_id;
    }

    if (sugg_code != KHERR_SUGGEST_NONE)
        *suggest_code = sugg_code;
}