示例#1
0
VOID
VdcadminSetSRPAuthData(
    VOID
    )
{
    CHAR inBuf[512] = {0};
    DWORD dwError = 0;

    if (pszUserName)
    {
        free(pszUserName);
    }
    if (pszDomain)
    {
        free(pszDomain);
    }
    if (pszPassword)
    {
        free(pszPassword);
    }
    VmDirReadString(
        "VMDIR IP address: ",
        inBuf,
        sizeof(inBuf),
        FALSE);
    if (inBuf[0])
    {
        pszNetworkAddress = strdup(inBuf);
    }

    VmDirReadString(
        "SRP Username: "******"SRP Domain: ",
        inBuf,
        sizeof(inBuf),
        FALSE);
    if (inBuf[0])
    {
        pszDomain = strdup(inBuf);
    }

    VmDirReadString(
        "SRP Password: "******"VmDirCreateBindingHandleAuthA: failed %x\n", dwError);
    }

    dwError = VmDirOpenServerA(
                  pszNetworkAddress,
                  pszUserName,
                  pszDomain,
                  pszPassword,
                  0,
                  NULL,
                  &g_hServer);
    if (dwError)
    {
        printf("VmDirOpenServerA: failed %x\n", dwError);
    }
}
示例#2
0
static
OM_uint32
_srp_gss_auth_init(
    OM_uint32 *minor_status,
    srp_gss_ctx_id_t srp_context_handle,
    int state,
    gss_buffer_t input_token,
    gss_buffer_t output_token)
{
    ber_tag_t ber_state = 0;
    struct berval ber_ctx = {0};
    struct berval *ber_upn = NULL;
    struct berval *ber_bytes_A = NULL;
    struct berval ber_salt = {0};
    struct berval ber_mda = {0};
    struct berval ber_B = {0};
    struct berval *flatten = NULL;
    BerElement *ber = NULL;
    BerElement *ber_resp = NULL;
    int berror = 0;
    int sts = 0;
    OM_uint32 maj = 0;
    OM_uint32 min = 0;
    OM_uint32 min_tmp = 0;
    gss_buffer_desc tmp_in_tok = {0};
    gss_buffer_desc disp_name_buf = {0};
    gss_buffer_t disp_name = NULL;
    gss_OID disp_name_OID = NULL;
    char *srp_upn_name = NULL;
    int srp_decode_mda_len = 0;
    int srp_decode_salt_len = 0;
    const unsigned char *srp_mda = NULL;
    const unsigned char *srp_salt = NULL;
    SRP_HashAlgorithm hash_alg = SRP_SHA1;
    SRP_NGType ng_type = SRP_NG_2048;
    struct SRPVerifier *ver = NULL;
    const unsigned char *srp_bytes_B = NULL;
    int srp_bytes_B_len = 0;
    const unsigned char *srp_session_key = NULL;
    unsigned char *ret_srp_session_key = NULL;
    int srp_session_key_len = 0;
    ber_int_t gss_srp_version_maj = 0;
    ber_int_t gss_srp_version_min = 0;
    PVMDIR_SERVER_CONTEXT hServer = NULL;
    srp_verifier_handle_t hSrp = NULL; /* aliased / cast to "ver" variable */
    srp_secret_blob_data srp_data = {0};
    int bUseCSRP = 0; /* Use CRP library directly */

    ber_ctx.bv_val = (void *) input_token->value;
    ber_ctx.bv_len = input_token->length;
    ber = ber_init(&ber_ctx);
    if (!ber)
    {
        maj = GSS_S_FAILURE;
        goto error;
    }

    srp_debug_printf("_srp_gss_auth_init(): state=SRP_AUTH_INIT\n");

    /*
     * ptr points to ASN.1 encoded data which is dependent on the authentication
     * state. The appropriate decoder format string is applied for each state
     */
    berror = ber_scanf(ber, "t{ii",
                       &ber_state, &gss_srp_version_maj, &gss_srp_version_min);
    if (berror == -1)
    {
        srp_debug_printf("_srp_gss_auth_init() ber_scanf(t{ii): failed berror=%d\n", berror);
        maj = GSS_S_FAILURE;
        goto error;
    }
    berror = ber_scanf(ber, "OO}", &ber_upn, &ber_bytes_A);
    if (berror == -1)
    {
        srp_debug_printf("_srp_gss_auth_init() ber_scanf(OO): failed berror=%d\n", berror);
        maj = GSS_S_FAILURE;
        goto error;
    }

    srp_debug_printf("_srp_gss_auth_init(accept_sec_context): protocol version %d.%d\n",
                     gss_srp_version_maj, gss_srp_version_min);
    srp_print_hex(ber_bytes_A->bv_val,
                  (int) ber_bytes_A->bv_len,
                  "_srp_gss_auth_init(accept_sec_context): bytes_A");
    /*
     * This is mostly impossible, as state IS the "t" field.
     * More a double check for proper decoding.
     */
    if ((int) ber_state != state)
    {
        maj = GSS_S_FAILURE;
        goto error;
    }

    tmp_in_tok.value = ber_upn->bv_val;
    tmp_in_tok.length = ber_upn->bv_len;
    maj = gss_import_name(&min,
                          &tmp_in_tok,
                          NULL,
                          &srp_context_handle->gss_upn_name);
    if (maj)
    {
        srp_debug_printf("_srp_gss_auth_init() gss_import_name failed maj=%d\n", maj);
        goto error;
    }

    maj = gss_display_name(&min,
                           srp_context_handle->gss_upn_name,
                           &disp_name_buf,
                           &disp_name_OID);
    if (maj)
    {
        srp_debug_printf("_srp_gss_auth_init() gss_display_name failed maj=%d\n", maj);
        goto error;
    }

    disp_name = &disp_name_buf;
    srp_debug_printf("_srp_gss_auth_init() srp_gss_accept_sec_context: UPN name=%.*s\n",
                     (int) disp_name_buf.length, (char *) disp_name_buf.value);

    srp_upn_name = calloc(disp_name_buf.length + 1, sizeof(char));
    if (!srp_upn_name)
    {
        maj = GSS_S_FAILURE;
        min = ENOMEM;
        goto error;
    }
    snprintf(srp_upn_name,
             disp_name_buf.length+1,
             "%.*s",
             (int) disp_name_buf.length,
             (char *) disp_name_buf.value);


    maj = _srp_gss_auth_create_machine_acct_binding(
              &bUseCSRP,
              &min,
              &hServer);
    if (maj)
    {
        srp_debug_printf("_srp_gss_auth_init() _srp_gss_auth_create_machine_acct_binding failed maj=%d\n", maj);
        maj = GSS_S_FAILURE;
        goto error;
    }

    if (!bUseCSRP)
    {
        sts = cli_rpc_srp_verifier_new(
                hServer ? hServer->hBinding : NULL,
                hash_alg,
                ng_type,
                srp_upn_name,
                ber_bytes_A->bv_val, (int) ber_bytes_A->bv_len,
                &srp_bytes_B, &srp_bytes_B_len,
                &srp_salt, &srp_decode_salt_len,
                &srp_mda, &srp_decode_mda_len,
                NULL, NULL, /* n_hex, g_hex */
                &hSrp);
        if (sts)
        {
            srp_debug_printf("_srp_gss_auth_init() cli_rpc_srp_verifier_new: failed sts=%d\n", sts);
            maj = GSS_S_FAILURE;
            min = sts;
            goto error;
        }
        ver = (struct SRPVerifier *) hSrp, hSrp = NULL;
    }
    else
    {
        sts = _get_srp_secret_decoded(
                  srp_upn_name,
                  &srp_data);
        if (sts)
        {
            srp_debug_printf("_srp_gss_auth_init() _get_srp_secret_decoded: failed sts=%d\n", sts);
            maj = GSS_S_FAILURE;
            min = sts;
            goto error;
        }

        /* Call SRP library implementation directly */
        ver =  srp_verifier_new(hash_alg, 
                                ng_type,
                                srp_upn_name,

                                /* SRP Salt value */
                                srp_data.salt, srp_data.salt_len,

                                /* SRP "V" verifier secret */
                                srp_data.v, srp_data.v_len,

                                /* SRP bytes_A */
                                ber_bytes_A->bv_val, (int) ber_bytes_A->bv_len,

                                /* SRP bytes B */
                                &srp_bytes_B, &srp_bytes_B_len,

                                /* SRP n_hex / g_hex */
                                NULL, NULL);
        if (!ver)
        {
            srp_debug_printf("_srp_gss_auth_init() srp_verifier_new: failed sts=%d\n", sts);
            maj = GSS_S_FAILURE;
            goto error;
        }
        srp_salt = srp_data.salt;
        srp_decode_salt_len = srp_data.salt_len;

    }

    if (!srp_bytes_B)
    {
        srp_debug_printf("_srp_gss_auth_init() srp_verifier_new: failed!\n");
        maj = GSS_S_FAILURE;
        goto error;
    }

    srp_print_hex(srp_salt, srp_decode_salt_len,
                  "_srp_gss_auth_init(accept_sec_context): srp_salt value");
    srp_print_hex(srp_bytes_B, srp_bytes_B_len,
                  "_srp_gss_auth_init(accept_sec_context): srp_B value");
    ber_mda.bv_val = (unsigned char *) srp_mda;
    ber_mda.bv_len = srp_decode_mda_len;

    ber_salt.bv_val = (unsigned char *) srp_salt;
    ber_salt.bv_len = srp_decode_salt_len;
    /*
     * B is computed: (kv + g**b) % N
     */
    ber_B.bv_val = (void *) srp_bytes_B;
    ber_B.bv_len = srp_bytes_B_len;

    ber_resp = ber_alloc_t(LBER_USE_DER);
    if (!ber_resp)
    {
        maj = GSS_S_FAILURE;
        min = ENOMEM;
        goto error;
    }

    /*
     * Response format:
     * tag | MDA | salt | B
     */
    berror = ber_printf(ber_resp, "t{OOO}",
                 SRP_AUTH_SALT_RESP,
                 &ber_mda,
                 &ber_salt,
                 &ber_B);
    if (berror == -1)
    {
        srp_debug_printf("_srp_gss_auth_init() ber_printf: failed berror=%d\n", berror);
        maj = GSS_S_FAILURE;
        goto error;
    }

    berror = ber_flatten(ber_resp, &flatten);
    if (berror == -1)
    {
        srp_debug_printf("_srp_gss_auth_init() ber_flatten: failed berror=%d\n", berror);
        maj = GSS_S_FAILURE;
        goto error;
    }

    output_token->value = gssalloc_calloc(1, flatten->bv_len);
    if (!output_token->value)
    {
        maj = GSS_S_FAILURE;
        goto error;
    }
    output_token->length = flatten->bv_len;
    memcpy(output_token->value, flatten->bv_val, flatten->bv_len);

    if (bUseCSRP)
    {
        srp_session_key = srp_verifier_get_session_key(ver, &srp_session_key_len);
    }
    else
    {
        sts = cli_rpc_srp_verifier_get_session_key(
            hServer ? hServer->hBinding : NULL,
            ver,
            &srp_session_key,
            &srp_session_key_len);
        if (sts)
        {
            min = sts;
            maj = GSS_S_FAILURE;
            goto error;
        }

    }

    if (srp_session_key && srp_session_key_len > 0)
    {
        ret_srp_session_key =
            calloc(srp_session_key_len, sizeof(unsigned char));
        if (!ret_srp_session_key)
        {
            maj = GSS_S_FAILURE;
            min = ENOMEM;
            goto error;
        }
    }
    memcpy(ret_srp_session_key,
           srp_session_key,
           srp_session_key_len);

    /* Set context handle/return values here; all previous calls succeeded */
    maj = GSS_S_CONTINUE_NEEDED;
    srp_context_handle->hServer = hServer, hServer = NULL;

    /* Used in generating Kerberos keyblock salt value */
    srp_context_handle->upn_name = srp_upn_name, srp_upn_name = NULL;
    srp_context_handle->srp_ver = ver, ver = NULL;

    /* Return the SRP session key in the context handle */
    srp_context_handle->srp_session_key_len = srp_session_key_len;
    srp_context_handle->srp_session_key = ret_srp_session_key, ret_srp_session_key = NULL;
    srp_context_handle->bUseCSRP = bUseCSRP;

    srp_print_hex(srp_session_key, srp_session_key_len,
                  "_srp_gss_auth_init(accept_sec_ctx) got session key");

error:
    if (ver)
    {
        if (bUseCSRP)
        {
            srp_verifier_delete(ver);
        }
        else
        {
            cli_rpc_srp_verifier_delete(
                hServer ? hServer->hBinding : NULL,
                (void **) &ver);
        }
    }
    VmDirCloseServer(hServer);
    if (srp_upn_name)
    {
        free(srp_upn_name);
    }
    if (ber_upn)
    {
        ber_bvfree(ber_upn);
    }
    if (ber_bytes_A)
    {
        ber_bvfree(ber_bytes_A);
    }
    ber_bvfree(flatten);
    ber_free(ber, 1);
    ber_free(ber_resp, 1);

    if (disp_name)
    {
        gss_release_buffer(&min_tmp, disp_name);
    }
    if (!bUseCSRP && srp_bytes_B)
    {
        free((void *) srp_bytes_B);
    }
    if (!bUseCSRP && srp_salt)
    {
        free((void *) srp_salt);
    }
    if (srp_mda)
    {
        free((void *) srp_mda);
    }
    if (!bUseCSRP && srp_session_key)
    {
        free((void *) srp_session_key);
    }
    if (bUseCSRP)
    {
        _free_srp_secret_decoded(&srp_data);
    }
    if (ret_srp_session_key)
    {
        free((void *) ret_srp_session_key);
    }

    if (maj)
    {
        if (min)
        {
            *minor_status = min;
        }
    }
    return maj;
}
示例#3
0
static
int
_VmDirGetRemoteDBUsingRPC(
    PCSTR   pszHostname,
    PCSTR   dbHomeDir,
    BOOLEAN *pbHasXlog)
{
    DWORD       retVal = 0;
    PSTR        pszLocalErrorMsg = NULL;
    char        dbRemoteFilename[VMDIR_MAX_FILE_NAME_LEN] = {0};
    char        localDir[VMDIR_MAX_FILE_NAME_LEN] = {0};
    char        localXlogDir[VMDIR_MAX_FILE_NAME_LEN] = {0};
    char        localFilename[VMDIR_MAX_FILE_NAME_LEN] = {0};
    PSTR        pszDcAccountPwd = NULL;
    PVMDIR_SERVER_CONTEXT hServer = NULL;
    DWORD       low_xlognum = 0;
    DWORD       high_xlognum = 0;
    DWORD       xlognum = 0;
    DWORD       remoteDbSizeMb = 0;
    DWORD       remoteDbMapSizeMb = 0;
    PBYTE       pDbPath = NULL;
    BOOLEAN     bMdbWalEnable = FALSE;

#ifndef _WIN32
    const char   fileSeperator = '/';
#else
    const char   fileSeperator = '\\';
#endif

    retVal = VmDirAllocateMemory(VMDIR_MAX_FILE_NAME_LEN, (PVOID)&pDbPath );
    BAIL_ON_VMDIR_ERROR(retVal);

    retVal = VmDirReadDCAccountPassword(&pszDcAccountPwd);
    BAIL_ON_VMDIR_ERROR( retVal );

    retVal = VmDirOpenServerA(pszHostname, gVmdirServerGlobals.dcAccountUPN.lberbv_val, NULL, pszDcAccountPwd, 0, NULL, &hServer);
    BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg),
            "_VmDirGetRemoteDBUsingRPC: VmDirOpenServerA() call failed with error: %d, host name = %s",
            retVal, pszHostname  );
    VMDIR_LOG_INFO( VMDIR_LOG_MASK_ALL, "_VmDirGetRemoteDBUsingRPC: Connected to the replication partner (%s).", pszHostname );

    VmDirGetMdbWalEnable(&bMdbWalEnable);

    if (bMdbWalEnable)
    {
        //Set remote server backend to KEEPXLOGS  mode
        retVal = VmDirSetBackendState (hServer, MDB_STATE_KEEPXLOGS, &low_xlognum, &remoteDbSizeMb,
                                       &remoteDbMapSizeMb, pDbPath, VMDIR_MAX_FILE_NAME_LEN);
    } else
    {
        //Set remote server backend to ReadOnly mode
        retVal = VmDirSetBackendState (hServer, MDB_STATE_READONLY, &low_xlognum, &remoteDbSizeMb,
                                       &remoteDbMapSizeMb, pDbPath, VMDIR_MAX_FILE_NAME_LEN);
    }
    BAIL_ON_VMDIR_ERROR_WITH_MSG(retVal, (pszLocalErrorMsg),
            "_VmDirGetRemoteDBUsingRPC: VmDirSetBackendState failed, WalEnabled: %d, error: %d", bMdbWalEnable, retVal);

    retVal = VmDirStringPrintFA( localDir, VMDIR_MAX_FILE_NAME_LEN, "%s%c%s", dbHomeDir, fileSeperator, LOCAL_PARTNER_DIR);
    BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg),
            "_VmDirGetRemoteDBUsingRPC: VmDirStringPrintFA() call failed with error: %d", retVal );

    retVal = _VmDirMkdir(localDir, 0700);
    BAIL_ON_VMDIR_ERROR( retVal );

    if (low_xlognum > 0)
    {
        retVal = VmDirStringPrintFA( localXlogDir, VMDIR_MAX_FILE_NAME_LEN, "%s%c%s", localDir, fileSeperator, VMDIR_MDB_XLOGS_DIR_NAME);
        BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg),
                "_VmDirGetRemoteDBUsingRPC: VmDirStringPrintFA() call failed with error: %d", retVal );

        retVal = _VmDirMkdir(localXlogDir, 0700);
        BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg),
                "_VmDirGetRemoteDBUsingRPC: _VmDirMkdir() call failed with error: %d %s", retVal );
    }

    retVal = VmDirStringPrintFA( dbRemoteFilename, VMDIR_MAX_FILE_NAME_LEN, "%s/%s", (char *)pDbPath,
                                 VMDIR_MDB_DATA_FILE_NAME );

    BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg),
            "_VmDirGetRemoteDBUsingRPC: VmDirStringPrintFA() call failed with error: %d", retVal );

    retVal = VmDirStringPrintFA( localFilename, VMDIR_MAX_FILE_NAME_LEN, "%s%c%s%c%s", dbHomeDir,
                                 fileSeperator, LOCAL_PARTNER_DIR, fileSeperator, VMDIR_MDB_DATA_FILE_NAME );

    BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg),
            "_VmDirGetRemoteDBUsingRPC: VmDirStringPrintFA() call failed with error: %d", retVal );

    VMDIR_LOG_INFO( VMDIR_LOG_MASK_ALL, "_VmDirGetRemoteDBUsingRPC: copying remote file %s with data size %ld MB with Map size %ld MB ...",
                    dbRemoteFilename, remoteDbSizeMb, remoteDbMapSizeMb );

    retVal = _VmDirGetRemoteDBFileUsingRPC( hServer, dbRemoteFilename, localFilename, remoteDbSizeMb, remoteDbMapSizeMb );
    BAIL_ON_VMDIR_ERROR( retVal );

    if (low_xlognum == 0)
    {
        VMDIR_LOG_INFO(VMDIR_LOG_MASK_ALL,
          "_VmDirGetRemoteDBUsingRPC: complete MDB cold copy - WAL not supported by remote");
        goto cleanup;
    }

    //Query current xlog number
    retVal = VmDirSetBackendState (hServer, MDB_STATE_GETXLOGNUM, &high_xlognum, &remoteDbSizeMb, &remoteDbMapSizeMb, pDbPath, VMDIR_MAX_FILE_NAME_LEN);
    BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg),
            "_VmDirGetRemoteDBUsingRPC: VmDirSetBackendState failed to get current xlog: %d", retVal  );

    VMDIR_LOG_INFO( VMDIR_LOG_MASK_ALL, "_VmDirGetRemoteDBUsingRPC: start transfering XLOGS from %d to %d", low_xlognum, high_xlognum);
    for (xlognum = low_xlognum; xlognum <= high_xlognum; xlognum++)
    {
        retVal = VmDirStringPrintFA( dbRemoteFilename, VMDIR_MAX_FILE_NAME_LEN, "%s%c%s%c%lu", dbHomeDir, fileSeperator,
                                 VMDIR_MDB_XLOGS_DIR_NAME, fileSeperator, xlognum );
        BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg),
            "_VmDirGetRemoteDBUsingRPC: VmDirStringPrintFA() call failed with error: %d", retVal );

        retVal = VmDirStringPrintFA( localFilename, VMDIR_MAX_FILE_NAME_LEN, "%s%c%lu", localXlogDir, fileSeperator, xlognum);
        BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg),
            "_VmDirGetRemoteDBUsingRPC: VmDirStringPrintFA() call failed with error: %d", retVal );

        retVal = _VmDirGetRemoteDBFileUsingRPC( hServer, dbRemoteFilename, localFilename, 0, 0);
        BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg),
            "_VmDirGetRemoteDBUsingRPC: _VmDirGetRemoteDBFileUsingRPC() call failed with error: %d", retVal );
    }

    VMDIR_LOG_INFO( VMDIR_LOG_MASK_ALL, "_VmDirGetRemoteDBUsingRPC: complete transfering XLOGS from %d to %d", low_xlognum, high_xlognum);

cleanup:
    if (hServer)
    {
        //clear backend transfering xlog files mode.
        VmDirSetBackendState (hServer, MDB_STATE_CLEAR, &xlognum, &remoteDbSizeMb, &remoteDbMapSizeMb, pDbPath, VMDIR_MAX_FILE_NAME_LEN);
        VmDirCloseServer( hServer);
    }
    VMDIR_SAFE_FREE_MEMORY(pszLocalErrorMsg);
    VMDIR_SAFE_FREE_MEMORY(pDbPath);
    VMDIR_SECURE_FREE_STRINGA(pszDcAccountPwd);
    *pbHasXlog = (low_xlognum > 0);
    return retVal;

error:
    retVal = LDAP_OPERATIONS_ERROR;
    VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "%s", VDIR_SAFE_STRING(pszLocalErrorMsg) );
    goto cleanup;
}
示例#4
0
OM_uint32
srp_gss_accept_sec_context(
                OM_uint32 *minor_status,
                gss_ctx_id_t *context_handle,
                gss_cred_id_t verifier_cred_handle,
                gss_buffer_t input_token,
                gss_channel_bindings_t input_chan_bindings,
                gss_name_t *src_name,
                gss_OID *mech_type,
                gss_buffer_t output_token,
                OM_uint32 *ret_flags,
                OM_uint32 *time_rec,
                gss_cred_id_t *delegated_cred_handle)
{
    int oid_len = 0;
    int state = 0;
    srp_gss_cred_id_t srp_cred = NULL;
    unsigned char *ptr = NULL;
    int ptr_len = 0;
    OM_uint32 maj = 0;
    OM_uint32 min = 0;
    OM_uint32 tmp_maj = 0;
    OM_uint32 tmp_min = 0;
    gss_buffer_desc input_token_srp = {0};
    srp_gss_ctx_id_t srp_context_handle = NULL;
    krb5_error_code krb5_err = 0;
    gss_cred_id_t srp_cred_handle = NULL;

    if (minor_status == NULL ||
        output_token == GSS_C_NO_BUFFER ||
        context_handle == NULL)
    {
        return GSS_S_CALL_INACCESSIBLE_WRITE;
    }

    if (input_token == GSS_C_NO_BUFFER)
    {
        return GSS_S_CALL_INACCESSIBLE_READ;
    }

    if (minor_status)
    {
        *minor_status = 0;
    }

    if (output_token != GSS_C_NO_BUFFER)
    {
        output_token->length = 0;
        output_token->value = NULL;
    }

    if (!context_handle)
    {
        maj = GSS_S_FAILURE;
        goto error;
    }

    if (*context_handle)
    {
        srp_context_handle = (srp_gss_ctx_id_t) *context_handle;
    }
    else
    {
        /* First call, allocate context handle */
        srp_context_handle =
            (srp_gss_ctx_id_t) calloc(1, sizeof(srp_gss_ctx_id_rec));
        if (!srp_context_handle)
        {
            min = ENOMEM;
            maj = GSS_S_FAILURE;
            goto error;
        }
        memset(srp_context_handle, 0, sizeof(srp_gss_ctx_id_rec));

        /* Needed for Kerberos AES256-SHA1 keyblock generation */
        krb5_err = krb5_init_context(&srp_context_handle->krb5_ctx);
        if (krb5_err)
        {
            maj = GSS_S_FAILURE;
            min = krb5_err;
            goto error;
        }
        maj = srp_gss_acquire_cred(
                  &min,
                  GSS_C_NO_NAME,
                  0,
                  NULL,
                  GSS_C_ACCEPT,
                  &srp_cred_handle,
                  NULL,
                  NULL);
        if (maj)
        {
            goto error;
        }
        srp_cred = (srp_gss_cred_id_t) srp_cred_handle;
        srp_context_handle->magic_num = SRP_MAGIC_ID;

        maj = srp_gss_duplicate_oid(&min,
                                    srp_cred->srp_mech_oid,
                                    &srp_context_handle->mech);
        if (maj)
        {
            goto error;
        }

        srp_context_handle->state = SRP_AUTH_INIT;
        srp_context_handle->cred = (srp_gss_cred_id_t) verifier_cred_handle;
        *context_handle = (gss_ctx_id_t) srp_context_handle;
    }

    ptr = (unsigned char*) input_token->value;
    ptr_len = (int) input_token->length;
    maj = srp_gss_validate_oid_header(
              &min,
              input_token,
              &oid_len);
    if (maj)
    {
        goto error;
    }

    ptr += oid_len;
    ptr_len -= oid_len;
    input_token_srp.value = ptr;
    input_token_srp.length = ptr_len;

    /* This is the "t" field of ber_scanf() */
    state = SRP_AUTH_STATE_VALUE(ptr[0]);

    /* Verify state machine is consistent with expected state */
    state = SRP_AUTH_STATE_VALUE(ptr[0]);

    if (state != srp_context_handle->state)
    {
        maj = GSS_S_FAILURE;
        goto error;
    }

    switch(state)
    {
      case SRP_AUTH_INIT:
        srp_debug_printf("srp_gss_accept_sec_context: state=SRP_AUTH_INIT\n");
        maj = _srp_gss_auth_init(minor_status,
                                 srp_context_handle,
                                 state,
                                 &input_token_srp,
                                 output_token);
        if (maj)
        {
            if (maj == GSS_S_CONTINUE_NEEDED)
            {
                srp_context_handle->state = SRP_AUTH_CLIENT_VALIDATE;
            }
            goto error;
        }
        break;

      case SRP_AUTH_CLIENT_VALIDATE:
        srp_debug_printf("srp_gss_accept_sec_context: "
                         "state=SRP_AUTH_CLIENT_VALIDATE\n");
        maj = _srp_gss_validate_client(minor_status,
                                       srp_context_handle,
                                       state,
                                       &input_token_srp,
                                       output_token);
        if (maj != GSS_S_CONTINUE_NEEDED && maj != GSS_S_COMPLETE)
        {
            /* Hard error occurred */
            goto error;
        }

        srp_context_handle->state = SRP_AUTH_COMPLETE;
        if (mech_type)
        {
            /* The security mechanism with which the context was established.
             * If the security mechanism type is not required, specify NULL
             * for this parameter. The gss_OID value returned for this
             * parameter points to a read-only structure and must not be
             * released by the application.
             */
            *mech_type = srp_context_handle->mech;
        }

        if (src_name)
        {
            /* Optional: Return UPN name to caller */
            tmp_maj = gss_duplicate_name(
                      &tmp_min,
                      srp_context_handle->gss_upn_name,
                      src_name);
            if (tmp_maj)
            {
                maj = tmp_maj;
                *minor_status = tmp_min;
                goto error;
            }
        }
        break;

      /* This should never happen, but include for completeness-sake */
      case SRP_AUTH_COMPLETE:
        srp_debug_printf("srp_gss_accept_sec_context: "
                         "state=SRP_AUTH_COMPLETE\n");
        maj = GSS_S_COMPLETE;
        break;

      default:
        srp_debug_printf("srp_gss_accept_sec_context: state=UNKNOWN!!!\n");
        maj = GSS_S_FAILURE;
        goto error;
        break;
    }

    if (srp_context_handle->state == SRP_AUTH_COMPLETE)
    {
        PVMDIR_SERVER_CONTEXT hServer = srp_context_handle->hServer;

#ifdef SRP_FIPS_ENABLED
        krb5_err = srp_make_enc_keyblock_FIPS(srp_context_handle);
#else
        krb5_err = srp_make_enc_keyblock(srp_context_handle);
#endif
        if (krb5_err)
        {
            maj = GSS_S_FAILURE;
            min = krb5_err;
            goto error;
        }

        if (srp_context_handle->bUseCSRP)
        {
            srp_verifier_delete(srp_context_handle->srp_ver);
        }
        else
        {
            /* Clean up SRP server-side memory, then close the server context */
            cli_rpc_srp_verifier_delete(
                hServer->hBinding,
                (void **) &srp_context_handle->srp_ver);
    
            VmDirCloseServer(hServer);
            srp_context_handle->hServer = NULL;
        }
    }

error:
    if (maj != GSS_S_CONTINUE_NEEDED && maj != GSS_S_COMPLETE)
    {
        _srp_gss_accept_sec_ctx_error_resp(
            minor_status,
            output_token);
    }

    if (srp_cred_handle)
    {
        srp_gss_release_cred(&tmp_min, &srp_cred_handle);
    }
    return maj;
}