Ejemplo n.º 1
0
VOID
VmKdcFreeDirectoryEntry(
    PVMKDC_DIRECTORY_ENTRY pDirectoryEntry)
{
    if (pDirectoryEntry)
    {
        VMKDC_SAFE_FREE_STRINGA(pDirectoryEntry->princName);
        VMKDC_SAFE_FREE_KEYSET(pDirectoryEntry->keyset);
        VMKDC_SAFE_FREE_MEMORY(pDirectoryEntry);
    }
}
Ejemplo n.º 2
0
static
VOID
VmKdcRegConfigTableFreeContents(
    PVMKDC_CONFIG_ENTRY pCfgTable,
    DWORD dwNumEntries
    )
{
    DWORD iEntry = 0;

    for (; iEntry < dwNumEntries; iEntry++)
    {
        PVMKDC_CONFIG_ENTRY pEntry = &pCfgTable[iEntry];

        if (pEntry->Type == VMKDC_CONFIG_VALUE_TYPE_STRING)
        {
            VMKDC_SAFE_FREE_STRINGA(pEntry->cfgValue.pszValue);
        }
    }
}
Ejemplo n.º 3
0
static
DWORD
VmKdcRegConfigGetString(
    PVMKDC_CONFIG_CONNECTION_HANDLE pCfgHandle,
    PCSTR   pszSubKey,
    PCSTR   pszKeyName,
    PSTR    *ppszValue)
{
    DWORD dwError = 0;
    char szValue[VMKDC_MAX_CONFIG_VALUE_LENGTH] = {0};
    DWORD dwszValueSize = sizeof(szValue);
    PSTR pszValue = NULL;

    dwError = VmKdcRegGetValueA(
                pCfgHandle->hConnection,
                pCfgHandle->hKey,
                pszSubKey,
                pszKeyName,
                RRF_RT_REG_SZ,
                NULL,
                szValue,
                &dwszValueSize);
    BAIL_ON_VMKDC_ERROR(dwError);

    dwError = VmKdcAllocateStringA(szValue, &pszValue);
    BAIL_ON_VMKDC_ERROR(dwError);

    *ppszValue = pszValue;

cleanup:

    return dwError;

error:

    *ppszValue = NULL;

    VMKDC_SAFE_FREE_STRINGA(pszValue);

    goto cleanup;
}
Ejemplo n.º 4
0
DWORD
VmKdcInitializeDirectory(
    PVMKDC_GLOBALS pGlobals)
{
    DWORD dwError = 0;
    PBYTE pPrincKeyBlob = NULL;
    PVMKDC_KEY master = NULL;
    PVMKDC_KEY kmEncKey = NULL;
    PVMKDC_CRYPTO pCrypto = NULL;
    PVMKDC_DATA kmKey = NULL;
    PSTR pszMasterName = NULL;
    BOOLEAN     bInLock = FALSE;
#ifdef MIT_KERBEROS_DB
    PVMKDC_KEYTAB_HANDLE hKtFile = NULL;
    PVMKDC_MIT_KEYTAB_FILE ktEntry = NULL;  /* Typedef named "wrong" */
    PVMKDC_KEYSET pKmKeySet = NULL;
#else
    PCSTR pszRealm = NULL;
    DWORD dwPrincKeySize = 0;
#endif

    // wait until vmdir gVmdirKrbGlobals is initialized
    VMDIR_LOCK_MUTEX( bInLock, gVmdirKrbGlobals.pmutex);
    while ( gVmdirKrbGlobals.pszRealm == NULL       &&
            VmKdcdState() == VMKDCD_STARTUP
          )
    {
        VmDirConditionTimedWait( gVmdirKrbGlobals.pcond,
                                 gVmdirKrbGlobals.pmutex,
                                 1 * 1000); // wait 1 second
    }
    VMDIR_UNLOCK_MUTEX( bInLock, gVmdirKrbGlobals.pmutex);

#ifdef MIT_KERBEROS_DB
{
    /* MIT Principal DB stashed master keytab */
    PSTR pszMasterKt = "/storage/db/vmware-vmdir/master.kt";

    /* Open keytab */
    dwError = VmKdcParseKeyTabOpen(pszMasterKt, "r", &hKtFile);
    BAIL_ON_VMKDC_ERROR(dwError);

    /* Master keytab has only one entry */
    dwError = VmKdcParseKeyTabRead(hKtFile, &ktEntry);
    BAIL_ON_VMKDC_ERROR(dwError);

    /* Populate KDC master key structure entry */
    dwError = VmKdcMakeKey(
                  ktEntry->key->type,
                  1,
                  VMKDC_GET_PTR_DATA(ktEntry->key->data),
                  VMKDC_GET_LEN_DATA(ktEntry->key->data),
                  &master);
    BAIL_ON_VMKDC_ERROR(dwError);

    /* Retrieve K/M from MIT dump, and decrypt this entry */
    dwError = VmKdcAllocateStringPrintf(&pszMasterName,
                                        "K/M@%s", ktEntry->realm);
    BAIL_ON_VMKDC_ERROR(dwError);

    /* Get K/M entry for current realm */
    dwError = VmKdcGetUpnKeysMitDb(pszMasterName,
                                   MIT_KERBEROS_DB_NAME, NULL, /* Full UPN, already known */
                                   &pKmKeySet);
    BAIL_ON_VMKDC_ERROR(dwError);

    /* Decrypt K/M using stashed master key */
    dwError = VmKdcMakeKey(
                  pKmKeySet->encKeys[0]->keytype,
                  1,
                  VMKDC_GET_PTR_DATA(pKmKeySet->encKeys[0]->encdata->data),
                  VMKDC_GET_LEN_DATA(pKmKeySet->encKeys[0]->encdata->data),
                  &kmEncKey);
    BAIL_ON_VMKDC_ERROR(dwError);

    dwError = VmKdcInitCrypto(pGlobals->pKrb5Ctx, master, &pCrypto);
    BAIL_ON_VMKDC_ERROR(dwError);

    dwError = VmKdcCryptoDecrypt(pCrypto, 0, kmEncKey->data,  &kmKey);
    BAIL_ON_VMKDC_ERROR(dwError);

    if (VMKDC_GET_LEN_DATA(master->data) != VMKDC_GET_LEN_DATA(kmKey) ||
        memcmp(VMKDC_GET_PTR_DATA(master->data),
               VMKDC_GET_PTR_DATA(kmKey),
               VMKDC_GET_LEN_DATA(kmKey)))
    {
        // TBD: Not quite right error
        dwError = ERROR_ALLOC_KRB5_CRYPTO_CONTEXT;
        BAIL_ON_VMKDC_ERROR(dwError);
    }

    pthread_mutex_lock(&pGlobals->mutex);
    VMKDC_SAFE_FREE_KEY(pGlobals->masterKey);
    pGlobals->masterKey = master;
    master = NULL;
    pthread_mutex_unlock(&pGlobals->mutex);
}
#else
    if ( VmKdcdState() == VMKDCD_STARTUP )
    {
        VMKDC_SAFE_FREE_STRINGA( pGlobals->pszDefaultRealm );
        dwError = VmKdcAllocateStringA( gVmdirKrbGlobals.pszRealm, &pGlobals->pszDefaultRealm );
        BAIL_ON_VMKDC_ERROR(dwError);

        pszRealm = pGlobals->pszDefaultRealm;

        dwError = VmKdcDecodeMasterKey(
                        gVmdirKrbGlobals.bervMasterKey.lberbv.bv_val, //pMasterKeyBlob,
                        (DWORD) gVmdirKrbGlobals.bervMasterKey.lberbv.bv_len, //dwMasterKeySize,
                        &master);
        BAIL_ON_VMKDC_ERROR(dwError);

        dwError = VmKdcAllocateStringPrintf(&pszMasterName,
                                            "K/M@%s", pszRealm);
        BAIL_ON_VMKDC_ERROR(dwError);


        dwError = _VmKdcGetKrbUPNKey(
                      pszMasterName,
                      &pPrincKeyBlob,
                      &dwPrincKeySize);
        BAIL_ON_VMKDC_ERROR(dwError);


        /*
         * The K/M master key is ASN.1 encoded and encrypted in the master key
         */
        dwError = VmKdcDecodeMasterKey(
                      pPrincKeyBlob,
                      dwPrincKeySize,
                      &kmEncKey);
        BAIL_ON_VMKDC_ERROR(dwError);

        dwError = VmKdcInitCrypto(pGlobals->pKrb5Ctx, master, &pCrypto);
        BAIL_ON_VMKDC_ERROR(dwError);

        dwError = VmKdcCryptoDecrypt(pCrypto, 0, kmEncKey->data,  &kmKey);
        BAIL_ON_VMKDC_ERROR(dwError);

        if (VMKDC_GET_LEN_DATA(master->data) != VMKDC_GET_LEN_DATA(kmKey) ||
            memcmp(VMKDC_GET_PTR_DATA(master->data),
                   VMKDC_GET_PTR_DATA(kmKey),
                   VMKDC_GET_LEN_DATA(kmKey)))
        {
            // TBD: Not quite right error
            dwError = ERROR_ALLOC_KRB5_CRYPTO_CONTEXT;
            BAIL_ON_VMKDC_ERROR(dwError);
        }

        pthread_mutex_lock(&pGlobals->mutex);
        VMKDC_SAFE_FREE_KEY(pGlobals->masterKey);
        pGlobals->masterKey = master;
        master = NULL;
        pthread_mutex_unlock(&pGlobals->mutex);
    }
#endif

error:
#ifdef MIT_KERBEROS_DB
    VmKdcParseKeyTabFreeEntry(ktEntry);
    VmKdcParseKeyTabClose(hKtFile);
    VMKDC_SAFE_FREE_KEYSET(pKmKeySet);
#endif
    VMKDC_SAFE_FREE_STRINGA(pszMasterName);
    VMKDC_SAFE_FREE_MEMORY(pPrincKeyBlob);
    VMKDC_SAFE_FREE_KEY(kmEncKey);
    VMKDC_SAFE_FREE_KEY(master);
    VMKDC_SAFE_FREE_DATA(kmKey);
    VmKdcDestroyCrypto(pCrypto);

    VMDIR_UNLOCK_MUTEX( bInLock, gVmdirKrbGlobals.pmutex);

    return dwError;
}
Ejemplo n.º 5
0
DWORD
VmKdcSearchDirectory(
    PVMKDC_CONTEXT pContext,
    PVMKDC_PRINCIPAL pPrincipal,
    PVMKDC_DIRECTORY_ENTRY *ppRetDirectoryEntry)
{
    DWORD dwError = 0;
    PSTR pszPrincName = NULL;
    PVMKDC_KEYSET princKeySet = NULL;
    PVMKDC_DIRECTORY_ENTRY pDirectoryEntry = NULL;
    PVMKDC_DATA princAsn1KeyData = NULL;
    PBYTE pPrincAsn1KeyBlob = NULL;
#ifndef MIT_KERBEROS_DB
    DWORD dwPrincAsn1KeySize = 0;
#endif

    BAIL_ON_VMKDC_INVALID_POINTER(pContext, dwError);
    BAIL_ON_VMKDC_INVALID_POINTER(pPrincipal, dwError);
    BAIL_ON_VMKDC_INVALID_POINTER(ppRetDirectoryEntry, dwError);

    /*
     * When vmdir is unavailable, the master key will be NULL.
     */
    if (!pContext->pRequest->masterKey)
    {
        dwError = VMKDC_RPC_SERVER_NOTAVAIL;
        BAIL_ON_VMKDC_ERROR(dwError);
    }

    dwError = VmKdcUnparsePrincipalName(pPrincipal, &pszPrincName);
    BAIL_ON_VMKDC_ERROR(dwError);


#ifdef MIT_KERBEROS_DB
{
    /* Get K/M entry for current realm */
    dwError = VmKdcGetUpnKeysMitDb(pszPrincName,
                                   MIT_KERBEROS_DB_NAME,
                                   NULL, /* Full UPN, already known */
                                   &princKeySet);
    BAIL_ON_VMKDC_ERROR(dwError);
}
#else
    dwError = _VmKdcGetKrbUPNKey(pszPrincName, &pPrincAsn1KeyBlob, &dwPrincAsn1KeySize);
    BAIL_ON_VMKDC_ERROR(dwError);


    dwError = VmKdcAllocateData(
                  pPrincAsn1KeyBlob,
                  dwPrincAsn1KeySize,
                  &princAsn1KeyData);
    BAIL_ON_VMKDC_ERROR(dwError);

    dwError = VmKdcDecodeKeySet(princAsn1KeyData , &princKeySet);
    BAIL_ON_VMKDC_ERROR(dwError);

#endif
    dwError = VmKdcDecryptKeySet(pContext,
                                 pContext->pRequest->masterKey,
                                 princKeySet);
    BAIL_ON_VMKDC_ERROR(dwError);

    dwError = VmKdcAllocateMemory(sizeof(VMKDC_DIRECTORY_ENTRY),
                                  (PVOID*)&pDirectoryEntry);
    BAIL_ON_VMKDC_ERROR(dwError);

    pDirectoryEntry->princName = pszPrincName;
    pDirectoryEntry->keyset = princKeySet;
    *ppRetDirectoryEntry = pDirectoryEntry;

error:
    VMKDC_SAFE_FREE_DATA(princAsn1KeyData);
    VMKDC_SAFE_FREE_MEMORY(pPrincAsn1KeyBlob);
    if (dwError)
    {
        VMKDC_SAFE_FREE_KEYSET(princKeySet);
        VMKDC_SAFE_FREE_STRINGA(pszPrincName);
        VMKDC_SAFE_FREE_MEMORY(pDirectoryEntry);
    }
    return dwError;
}
Ejemplo n.º 6
0
static
DWORD
VmKdcProcessAsReq(
    PVMKDC_CONTEXT pContext,
    PVMKDC_DATA *ppKrbMsg)
{
    DWORD dwError = 0;
    DWORD dwError2 = 0;
    PVMKDC_ASREQ asRequest = NULL;
    PVMKDC_DATA krbMsg = NULL;
    PVMKDC_KEY pCKey = NULL;
    PVMKDC_KEY pSKey = NULL;
    PVMKDC_KEY pSessionKey = NULL;
    PVMKDC_PRINCIPAL pCname = NULL;
    PVMKDC_PRINCIPAL pSname = NULL;
    DWORD nonce = 0;
    PVMKDC_DATA pAsnData = NULL;
    PVMKDC_TICKET pTicket = NULL;
    PVMKDC_ASREP pAsRep = NULL;
    time_t t_start = 0;
    time_t t_end = 0;
    time_t *t_reqTill = NULL;
    time_t *renew_till = NULL;
    PVMKDC_DIRECTORY_ENTRY pClientEntry = NULL;
    PVMKDC_DIRECTORY_ENTRY pServerEntry = NULL;
    DWORD error_code = 0;
    PVMKDC_DATA e_data = NULL;
    PSTR pszClientName = NULL;
    VMKDC_TICKET_FLAGS flags = 0;
    time_t kdc_time = 0;
    time_t maxrt = 0;
    BOOLEAN renewable_ok = 0;

    dwError = VmKdcAllocateData(
                  pContext->pRequest->requestBuf,
                  pContext->pRequest->requestBufLen,
                  &pAsnData);
    BAIL_ON_VMKDC_ERROR(dwError);

    dwError = VmKdcDecodeAsReq(pAsnData, &asRequest);
    BAIL_ON_VMKDC_ERROR(dwError);

    pCname = asRequest->req_body.cname;
    pSname = asRequest->req_body.sname;
    nonce = asRequest->req_body.nonce;

/* RFC4120 Page 26
 * If the requested starttime is absent, indicates a time in the past,
 * or is within the window of acceptable clock skew for the KDC and the
 * POSTDATE option has not been specified, then the starttime of the
 * ticket is set to the authentication server's current time.  If it
 * indicates a time in the future beyond the acceptable clock skew, but
 * the POSTDATED option has not been specified, then the error
 * KDC_ERR_CANNOT_POSTDATE is returned.  Otherwise the requested
 * starttime is checked against the policy of the local realm (the
 * administrator might decide to prohibit certain types or ranges of
 * postdated tickets), and if the ticket's starttime is acceptable, it
 * is set as requested, and the INVALID flag is set in the new ticket.
 * The postdated ticket MUST be validated before use by presenting it to
 * the KDC after the starttime has been reached.
 */

    kdc_time = time(NULL);
    if (!asRequest->req_body.from ||
        *asRequest->req_body.from < kdc_time ||
        (abs((long) (*asRequest->req_body.from - kdc_time)) <
         pContext->pGlobals->iClockSkew))

    {
        t_start = kdc_time;
    }
    else
    {
        dwError = ERROR_CANNOT_POSTDATE;
        BAIL_ON_VMKDC_ERROR(dwError);
    }

/*
 * The expiration time of the ticket will be set to the earlier of the
 * requested endtime and a time determined by local policy, possibly by
 * using realm- or principal-specific factors.  For example, the
 * expiration time MAY be set to the earliest of the following:
 *
 *    *  The expiration time (endtime) requested in the KRB_AS_REQ
 *       message.
 *
 *    *  The ticket's starttime plus the maximum allowable lifetime
 *       associated with the client principal from the authentication
 *       server's database.
 *
 *    *  The ticket's starttime plus the maximum allowable lifetime
 *       associated with the server principal.
 *
 *    *  The ticket's starttime plus the maximum lifetime set by the
 *       policy of the local realm.
 *
 * If the requested expiration time minus the starttime (as determined
 * above) is less than a site-determined minimum lifetime, an error
 * message with code KDC_ERR_NEVER_VALID is returned.  If the requested
 * expiration time for the ticket exceeds what was determined as above,
 * and if the 'RENEWABLE-OK' option was requested, then the 'RENEWABLE'
 * flag is set in the new ticket, and the renew-till value is set as if
 * the 'RENEWABLE' option were requested (the field and option names are
 * described fully in Section 5.4.1).
 */

    t_end = t_start + pContext->pGlobals->iMaxLife;
    t_reqTill = asRequest->req_body.till;
    if (t_reqTill)
    {
        if (*t_reqTill > t_end)
        {
            renewable_ok = VMKDC_FLAG_ISSET(asRequest->req_body.kdc_options,
                                            VMKDC_KO_RENEWABLE_OK);
            if (renewable_ok)
            {
                maxrt = t_start + pContext->pGlobals->iMaxRenewableLife;
                if (*t_reqTill <= maxrt)
                {
                    renew_till = t_reqTill;
                }
                else
                {
                    renew_till = &maxrt;
                }
                VMKDC_FLAG_SET(flags, VMKDC_TF_RENEWABLE);
            }
        }
        else
        {
            t_end = *t_reqTill;
        }
    }
    if ((t_end - t_start) < pContext->pGlobals->iClockSkew)
    {
        dwError = ERROR_NEVER_VALID;
        BAIL_ON_VMKDC_ERROR(dwError);
    }

    dwError = VmKdcUnparsePrincipalName(pCname, &pszClientName);
    BAIL_ON_VMKDC_ERROR(dwError);

    VMDIR_LOG_INFO(VMDIR_LOG_MASK_ALL,
             "Received AS-REQ for client %s",
             pszClientName);

    /*
     * Get the client key
     */
    dwError = VmKdcSearchDirectory(
                  pContext,
                  pCname,
                  &pClientEntry);
    BAIL_ON_VMKDC_ERROR(dwError);

    /*
     * TBD: Adam below using first ENCTYPE req_body.etype.type[0];
     * Need to search for strongest supported between C/S and KDC policy
     */
    dwError = VmKdcFindKeyByEType(
                  pClientEntry,
                  asRequest->req_body.etype.type[0], // Use first ENCTYPE; need to search for strongest supported between C/S
                  &pCKey);
    BAIL_ON_VMKDC_ERROR(dwError);

    /*
     * Get the server key
     */
    dwError = VmKdcSearchDirectory(
                  pContext,
                  pSname,
                  &pServerEntry);
    BAIL_ON_VMKDC_ERROR(dwError);

    dwError = VmKdcFindKeyByEType(
                  pServerEntry,
                  asRequest->req_body.etype.type[0], // Use first ENCTYPE; need to search for strongest supported between C/S
                  &pSKey);
    BAIL_ON_VMKDC_ERROR(dwError);

    /*
     * Verify the preauthentication data.
     */
    dwError = VmKdcVerifyAsReqPaData(pContext, asRequest, pCKey);
    if (dwError == ERROR_NO_PREAUTH)
    {
        dwError2 = VmKdcBuildKrbErrorEData(pCKey, &e_data);
        BAIL_ON_VMKDC_ERROR(dwError2);
    }
    BAIL_ON_VMKDC_ERROR(dwError);

    /*
     * Create a random session key
     */
    dwError = VmKdcRandomKey(pContext,
                             asRequest->req_body.etype.type[0],
                             &pSessionKey);
    BAIL_ON_VMKDC_ERROR(dwError);

    VMKDC_FLAG_SET(flags, VMKDC_TF_INITIAL);
    VMKDC_FLAG_SET(flags, VMKDC_TF_PRE_AUTHENT);
    if (VMKDC_FLAG_ISSET(asRequest->req_body.kdc_options, VMKDC_KO_FORWARDABLE))
    {
        VMKDC_FLAG_SET(flags, VMKDC_TF_FORWARDABLE);
    }
    if (VMKDC_FLAG_ISSET(asRequest->req_body.kdc_options, VMKDC_KO_PROXIABLE))
    {
        VMKDC_FLAG_SET(flags, VMKDC_TF_PROXIABLE);
    }

    /*
     * Build a TICKET
     */
    dwError = VmKdcBuildTicket(pContext,
                               pCname,
                               pSname,
                               pSKey,      /* key */
                               pSessionKey,
                               flags,      /* flags */
                               NULL,       /* transited */
                               t_start,    /* authtime */
                               &t_start,   /* starttime */
                               t_end,      /* endtime */
                               renew_till, /* renew_till */
                               NULL,       /* caddr */
                               NULL,       /* authorization_data */
                               &pTicket);
    BAIL_ON_VMKDC_ERROR(dwError);

    /*
     * Build an AS-REP
     */
    dwError = VmKdcBuildAsRep(pContext,
                              pCname,
                              pSname,
                              pCKey,      /* key */
                              pSessionKey,
                              pTicket,
                              NULL,       /* last-req */
                              nonce,      /* nonce */
                              NULL,       /* key-expiration (optional) */
                              flags,      /* flags */
                              t_start,    /* authtime */
                              &t_start,   /* starttime (optional) */
                              t_end,      /* endtime */
                              renew_till, /* renew-till (optional) */
                              NULL,       /* caddr */
                              &pAsRep);
    BAIL_ON_VMKDC_ERROR(dwError);

    /*
     * ASN.1 encode the AS-REP, and send the response.
     */
    dwError = VmKdcEncodeAsRep(pAsRep, &krbMsg);
    BAIL_ON_VMKDC_ERROR(dwError);

    VMDIR_LOG_INFO(VMDIR_LOG_MASK_ALL,
             "Sending AS-REP for client %s",
             pszClientName);

    *ppKrbMsg = krbMsg;

error:
    switch (dwError)
    {
        case 0: /* success, don't set error_code */
            break;
        case ERROR_NO_PREAUTH:
            error_code = VMKDC_KDC_ERR_PREAUTH_REQUIRED;
            break;
        case ERROR_FAILED_PREAUTH:
            error_code = VMKDC_KDC_ERR_PREAUTH_FAILED;
            break;
        case VMKDC_RPC_SERVER_NOTAVAIL:
            /*
             * Clear the global masterKey so it can't be used when vmdir is unavailable.
             */
            VmKdcTerminateDirectory(pContext->pGlobals);
            VmKdcdStateSet(VMKDCD_STARTUP);
            error_code = VMKDC_KDC_ERR_SVC_UNAVAILABLE;
            break;
        case ERROR_CANNOT_POSTDATE:
            error_code = VMKDC_KDC_ERR_CANNOT_POSTDATE;
            break;
        case ERROR_NEVER_VALID:
            error_code = VMKDC_KDC_ERR_NEVER_VALID;
            break;
        case ERROR_NO_PRINC:
        case ERROR_NO_KEY_ETYPE:
        default:
            error_code = VMKDC_KDC_ERR_C_PRINCIPAL_UNKNOWN;
            break;
    }
    if (asRequest && pCname && pSname && error_code)
    {
        dwError = VmKdcBuildKrbError(
                          asRequest->pvno,
                          NULL, /* ctime */
                          time(NULL), /* stime */
                          error_code, /* error_code */
                          VMKDC_GET_PTR_DATA(pCname->realm), /* crealm */
                          pCname, /* cname */
                          VMKDC_GET_PTR_DATA(pSname->realm), /* realm */
                          pSname, /* sname */
                          NULL, /* e_text */
                          e_data, /* e_data */
                          &krbMsg);
        if (dwError == 0)
        {
            *ppKrbMsg = krbMsg;

            VMDIR_LOG_INFO(VMDIR_LOG_MASK_ALL,
                     "Sending KRB-ERROR %d for client %s",
                     error_code, pszClientName);
        }
        else
        {
            VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL,
                     "Failed to build KRB-ERROR %d for client %s",
                     error_code, pszClientName);
        }
    }
    else
    {
        VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL,
                 "VmKdcProcessAsRequest failed, error code: (%u)",
                 dwError);
    }
    VMKDC_SAFE_FREE_DATA(e_data);
    VMKDC_SAFE_FREE_DIRECTORY_ENTRY(pClientEntry);
    VMKDC_SAFE_FREE_DIRECTORY_ENTRY(pServerEntry);
    VMKDC_SAFE_FREE_ASREQ(asRequest);
    VMKDC_SAFE_FREE_ASREP(pAsRep);
    VMKDC_SAFE_FREE_KEY(pSessionKey);
    VMKDC_SAFE_FREE_TICKET(pTicket);
    VMKDC_SAFE_FREE_DATA(pAsnData);
    VMKDC_SAFE_FREE_STRINGA(pszClientName);

    return dwError;
}
Ejemplo n.º 7
0
static
DWORD
VmKdcProcessTgsReq(
    PVMKDC_CONTEXT pContext,
    PVMKDC_DATA *ppKrbMsg)
{
    DWORD dwError = 0;
    DWORD error_code = 0;
    PVMKDC_ASREQ tgsRequest = NULL;
    PVMKDC_DATA krbMsg = NULL;
    PVMKDC_KEY pSKey = NULL;
    PVMKDC_KEY pPresentedSKey = NULL;
    PVMKDC_KEY pSessionKey = NULL;
    PVMKDC_PRINCIPAL pSname = NULL;
    DWORD nonce = 0;
    PVMKDC_DATA pAsnData = NULL;
    PVMKDC_TICKET pTicket = NULL;
    PVMKDC_TGSREP pTgsRep = NULL;
    time_t t_start = 0;
    time_t t_end = 0;
    time_t *t_reqTill = NULL;
    time_t *renew_till = NULL;
    time_t kdc_time = 0;
    PVMKDC_METHOD_DATA pMethodData = NULL;
    PVMKDC_PADATA pPaData = NULL;
    PVMKDC_APREQ apReq = NULL;
    PVMKDC_ENCTICKETPART pEncTicketPart = NULL;
    PVMKDC_DATA pData = NULL;
    PVMKDC_AUTHENTICATOR pAuthenticator = NULL;
    PVMKDC_DIRECTORY_ENTRY pServerEntry = NULL;
    PVMKDC_DIRECTORY_ENTRY pDirectoryEntry = NULL;
    PSTR pszServerName = NULL;
    VMKDC_TICKET_FLAGS flags = 0;
    BOOLEAN renew = FALSE;

    dwError = VmKdcAllocateData(
                  pContext->pRequest->requestBuf,
                  pContext->pRequest->requestBufLen,
                  &pAsnData);
    BAIL_ON_VMKDC_ERROR(dwError);

    dwError = VmKdcDecodeTgsReq(pAsnData, &tgsRequest);
    BAIL_ON_VMKDC_ERROR(dwError);

    pSname = tgsRequest->req_body.sname;
    nonce = tgsRequest->req_body.nonce;
    pMethodData = tgsRequest->padata;

    dwError = VmKdcUnparsePrincipalName(pSname, &pszServerName);
    BAIL_ON_VMKDC_ERROR(dwError);

    VMDIR_LOG_INFO(VMDIR_LOG_MASK_ALL,
            "Received TGS-REQ for server %s",
            pszServerName);

    /*
     * Get the server key
     */
    dwError = VmKdcSearchDirectory(
                  pContext,
                  pSname,
                  &pServerEntry);
    BAIL_ON_VMKDC_ERROR(dwError);

    dwError = VmKdcFindKeyByEType(
                  pServerEntry,
                  tgsRequest->req_body.etype.type[0], // Use first ENCTYPE; need to search for strongest supported between C/S
                  &pSKey);
    BAIL_ON_VMKDC_ERROR(dwError);

    /*
     * Get the preauth
     */
    if (!pMethodData)
    {
        dwError = ERROR_PROTOCOL;
        BAIL_ON_VMKDC_ERROR(dwError);
    }
    dwError = VmKdcFindPaData(VMKDC_PADATA_AP_REQ, pMethodData, &pPaData);
    BAIL_ON_VMKDC_ERROR(dwError);

    /*
     * Decode the AP-REQ
     */
    dwError = VmKdcDecodeApReq(pPaData->data, &apReq);
    BAIL_ON_VMKDC_ERROR(dwError);

    /*
     * Get the key for the server principal in the ticket (krbtgt).
     */
    dwError = VmKdcSearchDirectory(
                  pContext,
                  apReq->ticket->sname,
                  &pDirectoryEntry);
    BAIL_ON_VMKDC_ERROR(dwError);

    dwError = VmKdcFindKeyByEType(
                  pDirectoryEntry,
                  tgsRequest->req_body.etype.type[0], // Use first ENCTYPE; need to search for strongest supported between C/S
                  &pPresentedSKey);
    BAIL_ON_VMKDC_ERROR(dwError);

    /*
     * Decrypt the encrypted part of the ticket
     */
    dwError = VmKdcDecryptEncData(pContext,
                                  pPresentedSKey,
                                  VMKDC_KU_TICKET,
                                  apReq->ticket->enc_part,
                                  &pData);
    BAIL_ON_VMKDC_ERROR(dwError);

    /*
     * Decode the encrypted part of the ticket
     */
    dwError = VmKdcDecodeEncTicketPart(pData, &pEncTicketPart);
    BAIL_ON_VMKDC_ERROR(dwError);

    VMKDC_SAFE_FREE_DATA(pData);

    /*
     * Decrypt the authenticator
     */
    dwError = VmKdcDecryptEncData(pContext,
                                  pEncTicketPart->key,
                                  VMKDC_KU_TGS_REQ_AUTH,
                                  apReq->authenticator,
                                  &pData);
    BAIL_ON_VMKDC_ERROR(dwError);

    /*
     * Decode the authenticator
     */
    dwError = VmKdcDecodeAuthenticator(pData, &pAuthenticator);
    BAIL_ON_VMKDC_ERROR(dwError);

    /*
     * Create a random session key
     */
    dwError = VmKdcRandomKey(pContext,
                             tgsRequest->req_body.etype.type[0],
                             &pSessionKey);
    BAIL_ON_VMKDC_ERROR(dwError);

/*  RFC 4120, section 3.3.3, page 38
 *  By default, the address field, the client's name and realm, the list
 *  of transited realms, the time of initial authentication, the
 *  expiration time, and the authorization data of the newly-issued
 *  ticket will be copied from the TGT or renewable ticket.  If the
 *  transited field needs to be updated, but the transited type is not
 *  supported, the KDC_ERR_TRTYPE_NOSUPP error is returned.
 */

    kdc_time = time(NULL);
    if (!tgsRequest->req_body.from ||
        *tgsRequest->req_body.from < kdc_time ||
        (abs((long) (*tgsRequest->req_body.from - kdc_time)) <
         pContext->pGlobals->iClockSkew))
    {
        t_start = kdc_time;
    }
    else
    {
        dwError = ERROR_CANNOT_POSTDATE;
        BAIL_ON_VMKDC_ERROR(dwError);
    }

/*
 * If the request specifies an endtime, then the endtime of the new
 * ticket is set to the minimum of (a) that request, (b) the endtime
 * from the TGT, and (c) the starttime of the TGT plus the minimum of
 * the maximum life for the application server and the maximum life for
 * the local realm (the maximum life for the requesting principal was
 * already applied when the TGT was issued).  If the new ticket is to be
 * a renewal, then the endtime above is replaced by the minimum of (a)
 * the value of the renew_till field of the ticket and (b) the starttime
 * for the new ticket plus the life (endtime-starttime) of the old
 * ticket.
 */

    renew = VMKDC_FLAG_ISSET(tgsRequest->req_body.kdc_options, VMKDC_KO_RENEW);
    if (renew)
    {
        t_end = t_start + (pEncTicketPart->endtime - *pEncTicketPart->starttime);
        renew_till = pEncTicketPart->renew_till;
        if (*renew_till < t_end)
        {
            t_end = *renew_till;
        }
    }
    else
    {
        t_end = *pEncTicketPart->starttime + pContext->pGlobals->iMaxLife;
        t_reqTill = tgsRequest->req_body.till;
        if (t_reqTill)
        {
            if (*t_reqTill < t_end)
            {
                t_end = *t_reqTill;
            }
            if (pEncTicketPart->endtime < t_end)
            {
                t_end = pEncTicketPart->endtime;
            }
        }
    }

    VMKDC_FLAG_SET(flags, VMKDC_TF_INITIAL);
    VMKDC_FLAG_SET(flags, VMKDC_TF_PRE_AUTHENT);
    if (VMKDC_FLAG_ISSET(tgsRequest->req_body.kdc_options, VMKDC_KO_RENEWABLE))
    {
        VMKDC_FLAG_SET(flags, VMKDC_TF_RENEWABLE);
    }
    if (VMKDC_FLAG_ISSET(tgsRequest->req_body.kdc_options, VMKDC_KO_FORWARDABLE))
    {
        VMKDC_FLAG_SET(flags, VMKDC_TF_FORWARDABLE);
    }
    if (VMKDC_FLAG_ISSET(tgsRequest->req_body.kdc_options, VMKDC_KO_PROXIABLE))
    {
        VMKDC_FLAG_SET(flags, VMKDC_TF_PROXIABLE);
    }

    /*
     * Build a TICKET
     */
    dwError = VmKdcBuildTicket(pContext,
                               pEncTicketPart->cname,
                               pSname,
                               pSKey,
                               pSessionKey,
                               flags,      /* flags */
                               NULL,       /* transited */
                               t_start,    /* authtime */
                               &t_start,   /* starttime */
                               t_end,      /* endtime */
                               renew_till, /* renew_till */
                               NULL,       /* caddr */
                               NULL,       /* authorization_data */
                               &pTicket);
    BAIL_ON_VMKDC_ERROR(dwError);

/*  RFC 4120, section 3.3.3, page 40
 *  The ciphertext part of the response in the KRB_TGS_REP message is
 *  encrypted in the sub-session key from the Authenticator, if present,
 *  or in the session key from the TGT.  It is not encrypted using the
 *  client's secret key.  Furthermore, the client's key's expiration date
 *  and the key version number fields are left out since these values are
 *  stored along with the client's database record, and that record is
 *  not needed to satisfy a request based on a TGT.
 */

    /*
     * Build a TGS-REP
     */
    dwError = VmKdcBuildTgsRep(pContext,
                               pEncTicketPart->cname,
                               pSname,
                               pEncTicketPart->key,
                               pAuthenticator->subkey,
                               pSessionKey,
                               pTicket,
                               NULL,       /* last-req */
                               nonce,      /* nonce */
                               NULL,       /* key-expiration (optional) */
                               flags,      /* flags */
                               t_start,    /* authtime */
                               &t_start,   /* starttime */
                               t_end,      /* endtime */
                               renew_till, /* renew-till (optional) */
                               NULL,       /* caddr */
                               &pTgsRep);
    BAIL_ON_VMKDC_ERROR(dwError);

    /*
     * ASN.1 encode the TGS-REP
     */
    dwError = VmKdcEncodeTgsRep(pTgsRep, &krbMsg);
    BAIL_ON_VMKDC_ERROR(dwError);

    VMDIR_LOG_INFO(VMDIR_LOG_MASK_ALL,
            "Sending TGS-REP for server %s",
            pszServerName);

    *ppKrbMsg = krbMsg;

error:
    switch (dwError)
    {
        case 0: /* success, don't set error_code */
            break;
        case VMKDC_RPC_SERVER_NOTAVAIL:
            /*
             * Clear the global masterKey so it can't be used when vmdir is unavailable.
             */
            VmKdcTerminateDirectory(pContext->pGlobals);
            VmKdcdStateSet(VMKDCD_STARTUP);
            error_code = VMKDC_KDC_ERR_SVC_UNAVAILABLE;
            break;
        case ERROR_CANNOT_POSTDATE:
            error_code = VMKDC_KDC_ERR_CANNOT_POSTDATE;
            break;
        case ERROR_NO_PRINC:
        case ERROR_NO_KEY_ETYPE:
        default:
            error_code = VMKDC_KDC_ERR_C_PRINCIPAL_UNKNOWN;
            break;
    }
    if (tgsRequest && pSname && error_code)
    {
        dwError = VmKdcBuildKrbError(
                      tgsRequest->pvno,
                      NULL, /* ctime */
                      time(NULL), /* stime */
                      error_code, /* error_code */
                      NULL,
                      NULL,
                      VMKDC_GET_PTR_DATA(pSname->realm), /* realm */
                      pSname, /* sname */
                      NULL, /* e_text */
                      NULL, /* e_data */
                      &krbMsg);
        if (dwError == 0)
        {
            *ppKrbMsg = krbMsg;

            VMDIR_LOG_INFO(VMDIR_LOG_MASK_ALL,
                     "Sending KRB-ERROR %d for server %s",
                     error_code, pszServerName);
        }
        else
        {
            VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL,
                     "Failed to build KRB-ERROR %d for server %s",
                     error_code, pszServerName);
        }
    }
    else
    {
        VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL,
                 "VmKdcProcessTgsRequest failed, error code: (%u)",
                 dwError);
    }
    VMKDC_SAFE_FREE_DIRECTORY_ENTRY(pDirectoryEntry);
    VMKDC_SAFE_FREE_DIRECTORY_ENTRY(pServerEntry);
    VMKDC_SAFE_FREE_TGSREQ(tgsRequest);
    VMKDC_SAFE_FREE_TGSREP(pTgsRep);
    VMKDC_SAFE_FREE_APREQ(apReq);
    VMKDC_SAFE_FREE_ENCTICKETPART(pEncTicketPart);
    VMKDC_SAFE_FREE_AUTHENTICATOR(pAuthenticator);
    VMKDC_SAFE_FREE_DATA(pData);
    VMKDC_SAFE_FREE_KEY(pSessionKey);
    VMKDC_SAFE_FREE_TICKET(pTicket);
    VMKDC_SAFE_FREE_DATA(pAsnData);
    VMKDC_SAFE_FREE_STRINGA(pszServerName);

    return dwError;
}