Esempio n. 1
0
INTERNAL boolean conv_common
(
    dce_uuid_t *actuid,
    unsigned32 boot_time,
    rpc_dg_ccall_p_t *ccall,
    unsigned32 *st
)
{
    /*
     * Find the call he's asking about.
     */

    *ccall = rpc__dg_ccallt_lookup(actuid, RPC_C_DG_NO_HINT);

    /*
     * No ccall entry will exist if an old duplicate WAY callback request
     * is received.  If there is no ccall entry corresponding to the
     * incoming activity id then we return an error status code.  The
     * server performing the WAY callback will detect the error and send
     * a reject packet that will be dropped by the client.
     */

    if (*ccall == NULL) 
    {
        *st = nca_s_bad_actid;
        return (false);
    }

    /*
     * If we don't know the boot time yet for this server, stash it away
     * now.
     */

    if ((*ccall)->c.call_server_boot == 0)
    {
        (*ccall)->c.call_server_boot = boot_time;
    }
    else 
    {
        /*
         * We DO know the boot time.  If what the server's supplied boot
         * time isn't what we think it should be, then we must be getting
         * called back by a new instance of the server (i.e., which
         * received a duplicate of an outstanding request of ours).  Since
         * we can't know whether the original instance of the server
         * executed our call or not, we return failure to the server
         * to prevent IT from executing call (i.e., for a possible second
         * time, violating the "at most once" rule).
         */
        if ((*ccall)->c.call_server_boot != boot_time)
        {
            *st = nca_s_you_crashed;
            RPC_DG_CCALL_RELEASE(ccall);
            return (false);
        }
    }

    *st = rpc_s_ok;
    return (true);
}
Esempio n. 2
0
INTERNAL void release_cached_ccall
(
    rpc_dg_binding_client_p_t h
)
{
    if (h->ccall == NULL)
        return;

    RPC_DG_CALL_LOCK(&h->ccall->c);
    rpc__dg_ccall_free_prep(h->ccall);
    RPC_DG_CCALL_RELEASE(&h->ccall);
    /* unlocks as a side effect */
}
Esempio n. 3
0
PRIVATE void conv_are_you_there
(
    handle_t h ATTRIBUTE_UNUSED,       /* Not really */
    dce_uuid_t *actuid,
    unsigned32 boot_time,
    unsigned32 *st
)
{
    rpc_dg_ccall_p_t ccall;

    RPC_LOCK_ASSERT(0);

    if (! conv_common(actuid, boot_time, &ccall, st))
    {
        return;
    }

    RPC_DG_CCALL_RELEASE(&ccall);
} 
Esempio n. 4
0
INTERNAL boolean32 scall_uncache
(
    rpc_dg_scall_p_t scall
)
{
    unsigned32 st;
    boolean b;

    RPC_TRY_LOCK(&b);
    if (! b)
    {
        RPC_DBG_GPRINTF(("(scall_uncache) couldn't get global lock\n"));
        return false;
    }

    RPC_DG_CALL_LOCK_ASSERT(&scall->c);

    assert(scall->c.state == rpc_e_dg_cs_idle || scall->c.state == rpc_e_dg_cs_orphan);

    if (scall->c.is_cbk)
    {
        /*
         * This is a *client side* callback scall; dissociate from our
         * cbk_ccall if necessary.
         */
        if (scall->cbk_ccall != NULL)
        {
            rpc_dg_ccall_p_t ccall = scall->cbk_ccall;

            assert(ccall->cbk_scall == scall);

            /*
             * Acquire the callback ccall lock.  Note the locking hierarchy
             * for this type of call handle pairing is:  cbk_ccall, is_cbk scall
             * (see dg.h).
             */
            RPC_DG_CALL_TRY_LOCK(&ccall->c, &b);
            if (! b)
            {
                RPC_DBG_GPRINTF(
                    ("(scall_uncache) couldn't get cbk_scall->cbk_ccall lock\n"));
                RPC_UNLOCK(0);
                return false;
            }

            ccall->cbk_start = false;

            RPC_DG_CCALL_RELEASE(&scall->cbk_ccall);

            RPC_DG_SCALL_RELEASE_NO_UNLOCK(&ccall->cbk_scall);
        }
    }
    else
    {
        /*
         * This is a normal (server side) scall.
         */

        /*
         * If this server side scall has been part of a callback back
         * to the client, free up the cached *server side* callback ccall
         * resources.
         */

        if (scall->cbk_ccall != NULL)
        {
            rpc_dg_ccall_p_t ccall = scall->cbk_ccall;

            assert(ccall->cbk_scall == scall);

            /*
             * Acquire the callback ccall lock.  Note the locking hierarchy
             * for this type of call handle pairing is:  scall, is_cbk ccall
             * (see dg.h).
             */
            RPC_DG_CALL_LOCK(&ccall->c);

            rpc__dg_ccall_free_prep(ccall);

            /*
             * Release the reference the CCALL has to its originating SCALL.
             */

            RPC_DG_SCALL_RELEASE_NO_UNLOCK(&ccall->cbk_scall);

            /*
             * Release the reference the SCALL has to the CCALL it used for
             * the callback.  Then call free_handle, which will stop the
             * timer and release the client binding handles reference to
             * the CCALL.
             */

            RPC_DG_CCALL_RELEASE(&scall->cbk_ccall);
            RPC_BINDING_RELEASE((rpc_binding_rep_p_t *) &ccall->h, &st);
        }

        /*
         * Dissociate the scall from its scte if necessary. Presumably,
         * the only time that the scall won't have a scte is if the call
         * had been orphaned, though we don't count on that.
         */

        if (scall->scte != NULL)
        {
            release_scall_from_scte(scall);

            /*
             * Release the SCALL's reference to the SCTE.
             */

            RPC_DG_SCT_RELEASE(&scall->scte);
        }
    }

    /*
     * Common scall uncache processing.
     */

    RPC_DBG_PRINTF(rpc_e_dbg_general, 3,
                ("(scall_uncache) Freeing cached SCALL [%s]\n",
                rpc__dg_act_seq_string(&scall->c.xq.hdr)));

    /*
     * Dissociate the scall from the server binding handle if necessary.
     */

    if (scall->h != NULL)
    {
        RPC_DG_SCALL_RELEASE_NO_UNLOCK(&scall->h->scall);
        RPC_BINDING_RELEASE((rpc_binding_rep_p_t *) &scall->h, &st);
    }

    /*
     * Stop the scall's timer and dissociate it from the scall.
     */

    rpc__timer_clear(&scall->c.timer);
    RPC_DG_SCALL_RELEASE(&scall);

    RPC_UNLOCK(0);
    return true;
}
Esempio n. 5
0
PRIVATE void conv_who_are_you_auth 
(
    handle_t h ATTRIBUTE_UNUSED, /* not really */
    dce_uuid_t *actuid,
    unsigned32 boot_time,
    ndr_byte *in_data,
    signed32 in_len,
    signed32 out_max_len,
    unsigned32 *seq,
    dce_uuid_t *cas_uuid,
    ndr_byte *out_data,
    signed32 *out_len,
    unsigned32 *st
)
{
    rpc_dg_ccall_p_t ccall;
    rpc_dg_auth_epv_p_t epv;
    ndr_byte *save_out_data = out_data;
    
    RPC_LOCK_ASSERT(0);
    
    if (! conv_common(actuid, boot_time, &ccall, st))
    {
        return;
    }

    *cas_uuid = rpc_g_dg_my_cas_uuid;
    *seq = ccall->c.call_seq;

    /*
     * If there's already a credentials buffer associated with this
     * call handle, free it.  We rely on the underlying security code
     * to do cacheing if appropriate.
     */
    if (ccall->auth_way_info != NULL)
    {
        RPC_MEM_FREE(ccall->auth_way_info, RPC_C_MEM_DG_EPAC);
        ccall->auth_way_info     = NULL;
        ccall->auth_way_info_len = 0;
    }

    /* 
     * Make sure that we really have an authenticated call here, 
     * lest we dereference null and blow up the process.
     */
    epv = ccall->c.auth_epv;
    if (epv == NULL) 
    {
        *st = rpc_s_binding_has_no_auth;
    } 
    else 
    {
	RPC_DG_CALL_UNLOCK(&(ccall->c));
	RPC_UNLOCK(0);
	
	(*epv->way_handler) (ccall->c.key_info, in_data, in_len,
            out_max_len, &out_data, out_len, st);

	RPC_LOCK(0);
	RPC_DG_CALL_LOCK(&(ccall->c));

        if (*out_len > out_max_len)
        {
            /*
             * If the credentials did not fit in the buffer provided,
             * the WAY handler will have alloced up a buffer big enough
             * to hold them, and returned a pointer to that storage in
             * out_data.  
             *
             * Stash a pointer to this buffer in the call handle, copy 
             * as much of the credentials as will fit in the real response 
             * packet, and return a status that indicates that the caller 
             * needs to fetch the rest of the credentials.
             */
            ccall->auth_way_info = out_data;
            ccall->auth_way_info_len = *out_len;

            memcpy(save_out_data, out_data, out_max_len);
            *out_len = out_max_len;

            *st = rpc_s_partial_credentials;
        }
    }
    RPC_DG_CCALL_RELEASE(&ccall);
}