static int gp_rpc_encode_reply_header(XDR *xdr_reply_ctx,
                                      uint32_t xid, int err,
                                      gp_rpc_accept_status acc,
                                      gp_rpc_reject_status rej)
{
    gp_rpc_msg msg;
    gp_rpc_reply_header *rhdr;
    gp_rpc_accepted_reply *accepted;
    gp_rpc_rejected_reply *rejected;
    bool encoded;

    memset(&msg, 0, sizeof(gp_rpc_msg));

    msg.xid = xid;
    msg.header.type = GP_RPC_REPLY;

    rhdr = &msg.header.gp_rpc_msg_union_u.rhdr;
    accepted = &rhdr->gp_rpc_reply_header_u.accepted;
    rejected = &rhdr->gp_rpc_reply_header_u.rejected;

    switch (err) {
    case EFAULT:
        return EFAULT;
    case EACCES:
        rhdr->status = GP_RPC_MSG_DENIED;
        rejected->status = rej;
        if (rej == GP_RPC_RPC_MISMATCH) {
            rejected->gp_rpc_rejected_reply_u.mismatch_info.high = 2;
            rejected->gp_rpc_rejected_reply_u.mismatch_info.low = 2;
        } else {
            rejected->gp_rpc_rejected_reply_u.status = GP_RPC_AUTH_FAILED;
        }
        break;
    case EINVAL:
        rhdr->status = GP_RPC_MSG_ACCEPTED;
        accepted->reply_data.status = acc;
        if (acc == GP_RPC_PROG_MISMATCH) {
            accepted->reply_data.gp_rpc_reply_union_u.mismatch_info.high = GSSPROXYVERS;
            accepted->reply_data.gp_rpc_reply_union_u.mismatch_info.low = GSSPROXYVERS;
        }
        break;
    case 0:
        rhdr->status = GP_RPC_MSG_ACCEPTED;
        accepted->reply_data.status = GP_RPC_SUCCESS;
        break;
    default:
        rhdr->status = GP_RPC_MSG_ACCEPTED;
        accepted->reply_data.status = GP_RPC_SYSTEM_ERR;
        break;
    }

    /* always reset xdr_ctx position, as this function may be called
     * multiple times in case errors occurred after the initial header
     * was created */
    xdr_setpos(xdr_reply_ctx, 0);

    encoded = xdr_gp_rpc_msg(xdr_reply_ctx, &msg);
    if (!encoded) {
        return EFAULT;
    }

    return 0;
}
Beispiel #2
0
int gpm_make_call(int proc, union gp_rpc_arg *arg, union gp_rpc_res *res)
{
    struct gpm_ctx *gpmctx;
    gp_rpc_msg msg;
    XDR xdr_call_ctx;
    XDR xdr_reply_ctx;
    char buffer[MAX_RPC_SIZE];
    uint32_t length;
    uint32_t xid;
    bool xdrok;
    bool sockgrab = false;
    int ret;

    xdrmem_create(&xdr_call_ctx, buffer, MAX_RPC_SIZE, XDR_ENCODE);
    xdrmem_create(&xdr_reply_ctx, buffer, MAX_RPC_SIZE, XDR_DECODE);

    memset(&msg, 0, sizeof(gp_rpc_msg));
    msg.header.type = GP_RPC_CALL;
    msg.header.gp_rpc_msg_union_u.chdr.rpcvers = 2;
    msg.header.gp_rpc_msg_union_u.chdr.prog = GSSPROXY;
    msg.header.gp_rpc_msg_union_u.chdr.vers = GSSPROXYVERS;
    msg.header.gp_rpc_msg_union_u.chdr.proc = proc;
    msg.header.gp_rpc_msg_union_u.chdr.cred.flavor = GP_RPC_AUTH_NONE;
    msg.header.gp_rpc_msg_union_u.chdr.cred.body.body_len = 0;
    msg.header.gp_rpc_msg_union_u.chdr.cred.body.body_val = NULL;
    msg.header.gp_rpc_msg_union_u.chdr.verf.flavor = GP_RPC_AUTH_NONE;
    msg.header.gp_rpc_msg_union_u.chdr.verf.body.body_len = 0;
    msg.header.gp_rpc_msg_union_u.chdr.verf.body.body_val = NULL;

    gpmctx = gpm_get_ctx();
    if (!gpmctx) {
        return EINVAL;
    }

    /* grab the lock for the whole conversation */
    ret = gpm_grab_sock(gpmctx);
    if (ret) {
        goto done;
    }
    sockgrab = true;

    msg.xid = xid = gpm_next_xid(gpmctx);

    /* encode header */
    xdrok = xdr_gp_rpc_msg(&xdr_call_ctx, &msg);
    if (!xdrok) {
        ret = EINVAL;
        goto done;
    }

    /* encode data */
    xdrok = gpm_xdr_set[proc].arg_fn(&xdr_call_ctx, (char *)arg);
    if (!xdrok) {
        ret = EINVAL;
        goto done;
    }

    /* send to proxy */
    ret = gpm_send_buffer(gpmctx, buffer, xdr_getpos(&xdr_call_ctx));
    if (ret) {
        goto done;
    }

    /* receive answer */
    ret = gpm_recv_buffer(gpmctx, buffer, &length);
    if (ret) {
        goto done;
    }

    /* release the lock */
    gpm_release_sock(gpmctx);
    sockgrab = false;

    /* decode header */
    memset(&msg, 0, sizeof(gp_rpc_msg));
    xdrok = xdr_gp_rpc_msg(&xdr_reply_ctx, &msg);
    if (!xdrok) {
        ret = EINVAL;
        goto done;
    }

    if (msg.xid != xid ||
        msg.header.type != GP_RPC_REPLY ||
        msg.header.gp_rpc_msg_union_u.rhdr.status != GP_RPC_MSG_ACCEPTED ||
        msg.header.gp_rpc_msg_union_u.rhdr.gp_rpc_reply_header_u.accepted.reply_data.status != GP_RPC_SUCCESS) {
        ret = EINVAL;
        goto done;
    }

    /* decode answer */
    xdrok = gpm_xdr_set[proc].res_fn(&xdr_reply_ctx, (char *)res);
    if (!xdrok) {
        ret = EINVAL;
    }

done:
    if (sockgrab) {
        gpm_release_sock(gpmctx);
    }
    xdr_free((xdrproc_t)xdr_gp_rpc_msg, (char *)&msg);
    xdr_destroy(&xdr_call_ctx);
    xdr_destroy(&xdr_reply_ctx);
    gpm_release_ctx(gpmctx);
    return ret;
}
static int gp_rpc_decode_call_header(XDR *xdr_call_ctx,
                                     uint32_t *xid,
                                     uint32_t *proc,
                                     gp_rpc_accept_status *acc,
                                     gp_rpc_reject_status *rej)
{
    struct gp_rpc_call_header *chdr;
    gp_rpc_msg msg;
    bool decoded;
    int ret;

    memset(&msg, 0, sizeof(gp_rpc_msg));

    decoded = xdr_gp_rpc_msg(xdr_call_ctx, &msg);
    if (!decoded) {
        return EFAULT;
    }

    *xid = msg.xid;

    if (msg.header.type != GP_RPC_CALL) {
        *acc = GP_RPC_GARBAGE_ARGS;
        ret = EINVAL;
        goto done;
    }

    chdr = &msg.header.gp_rpc_msg_union_u.chdr;

    if (chdr->rpcvers != 2) {
        *rej = GP_RPC_RPC_MISMATCH;
        ret = EACCES;
        goto done;
    }
    if (chdr->prog != GSSPROXY) {
        *acc = GP_RPC_PROG_UNAVAIL;
        ret = EINVAL;
        goto done;
    }
    if (chdr->vers != GSSPROXYVERS) {
        *acc = GP_RPC_PROG_MISMATCH;
        ret = EINVAL;
        goto done;
    }
    if (chdr->proc < GSSX_PROC_MIN || chdr->proc > GSSX_PROC_MAX) {
        *acc = GP_RPC_PROC_UNAVAIL;
        ret = EINVAL;
        goto done;
    }
    if (chdr->cred.flavor != GP_RPC_AUTH_NONE) {
        *rej = GP_RPC_AUTH_ERROR;
        ret = EACCES;
        goto done;
    }

    *proc = chdr->proc;
    *acc = GP_RPC_SUCCESS;
    ret = 0;

done:
    xdr_free((xdrproc_t)xdr_gp_rpc_msg, (char *)&msg);
    return ret;
}
Beispiel #4
0
int gp_send_accept_sec_context(int fd,
                               gssx_arg_accept_sec_context *arg,
                               gssx_res_accept_sec_context *res)
{
    XDR xdr_call_ctx;
    XDR xdr_reply_ctx;
    gp_rpc_msg msg;
    char buffer[MAX_RPC_SIZE];
    uint32_t length;
    bool xdrok;
    int ret;

    memset(&msg, 0, sizeof(gp_rpc_msg));

    xdrmem_create(&xdr_call_ctx, buffer, MAX_RPC_SIZE, XDR_ENCODE);
    xdrmem_create(&xdr_reply_ctx, buffer, MAX_RPC_SIZE, XDR_DECODE);

    msg.xid = 1;
    msg.header.type = GP_RPC_CALL;
    msg.header.gp_rpc_msg_union_u.chdr.rpcvers = 2;
    msg.header.gp_rpc_msg_union_u.chdr.prog = GSSPROXY;
    msg.header.gp_rpc_msg_union_u.chdr.vers = GSSPROXYVERS;
    msg.header.gp_rpc_msg_union_u.chdr.proc = GSSX_ACCEPT_SEC_CONTEXT;
    msg.header.gp_rpc_msg_union_u.chdr.cred.flavor = GP_RPC_AUTH_NONE;
    msg.header.gp_rpc_msg_union_u.chdr.cred.body.body_len = 0;
    msg.header.gp_rpc_msg_union_u.chdr.cred.body.body_val = NULL;
    msg.header.gp_rpc_msg_union_u.chdr.verf.flavor = GP_RPC_AUTH_NONE;
    msg.header.gp_rpc_msg_union_u.chdr.verf.body.body_len = 0;
    msg.header.gp_rpc_msg_union_u.chdr.verf.body.body_val = NULL;

    /* encode header */
    xdrok = xdr_gp_rpc_msg(&xdr_call_ctx, &msg);
    if (!xdrok) {
        return EFAULT;
    }

    /* encode data */
    xdrok = xdr_gssx_arg_accept_sec_context(&xdr_call_ctx, arg);
    if (!xdrok) {
        return EFAULT;
    }

    /* send to proxy */
    ret = t_send_buffer(fd, buffer, xdr_getpos(&xdr_call_ctx));
    if (ret) {
        return EIO;
    }

    /* receive answer */
    ret = t_recv_buffer(fd, buffer, &length);
    if (ret) {
        return EIO;
    }

    /* decode header */
    xdrok = xdr_gp_rpc_msg(&xdr_reply_ctx, &msg);
    if (!xdrok) {
        return EFAULT;
    }

    if (msg.xid != 1 ||
        msg.header.type != GP_RPC_REPLY ||
        msg.header.gp_rpc_msg_union_u.rhdr.status != GP_RPC_MSG_ACCEPTED ||
        msg.header.gp_rpc_msg_union_u.rhdr.gp_rpc_reply_header_u.accepted.reply_data.status != GP_RPC_SUCCESS) {
        return EINVAL;
    }

    /* decode answer */
    xdrok = xdr_gssx_res_accept_sec_context(&xdr_reply_ctx, res);
    if (!xdrok) {
        return EFAULT;
    }

    xdr_free((xdrproc_t)xdr_gp_rpc_msg, (char *)&msg);
    xdr_destroy(&xdr_call_ctx);
    xdr_destroy(&xdr_reply_ctx);
    return 0;
}