コード例 #1
0
ファイル: server-v1.c プロジェクト: moretension/remctl
/*
 * Takes the client struct and the server configuration and handles a client
 * request.  Reads a command from the client, checks the ACL, runs the command
 * if appropriate, and sends any output back to the client.
*/
void
server_v1_handle_messages(struct client *client, struct config *config)
{
    gss_buffer_desc token;
    OM_uint32 major, minor;
    struct iovec **argv = NULL;
    int status, flags;

    /* Receive the message. */
    status = token_recv_priv(client->fd, client->context, &flags, &token,
                             TOKEN_MAX_LENGTH, TIMEOUT, &major, &minor);
    if (status != TOKEN_OK) {
        warn_token("receiving command token", status, major, minor);
        if (status == TOKEN_FAIL_LARGE)
            server_send_error(client, ERROR_TOOMUCH_DATA, "Too much data");
        else if (status != TOKEN_FAIL_EOF)
            server_send_error(client, ERROR_BAD_TOKEN, "Invalid token");
        return;
    }

    /* Check the data size. */
    if (token.length > TOKEN_MAX_DATA) {
        warn("command data length %lu exceeds 64KB",
             (unsigned long) token.length);
        server_send_error(client, ERROR_TOOMUCH_DATA, "Too much data");
        gss_release_buffer(&minor, &token);
        return;
    }

    /*
     * Do the shared parsing of the message.  This code is identical to the
     * code for v2 (v2 just pulls more data off the front of the token first).
     */
    argv = server_parse_command(client, token.value, token.length);
    gss_release_buffer(&minor, &token);
    if (argv == NULL)
        return;

    /*
     * Check the ACL and existence of the command, run the command if
     * possible, and accumulate the output in the client struct.
     */
    server_run_command(client, config, argv);
    server_free_command(argv);
}
コード例 #2
0
ファイル: noop-t.c プロジェクト: mloar/remctl
int
main(void)
{
    struct kerberos_config *config;
    struct remctl *r;
    OM_uint32 major, minor;
    int flags, status;
    gss_buffer_desc tok;

    /* Unless we have Kerberos available, we can't really do anything. */
    config = kerberos_setup(TAP_KRB_NEEDS_KEYTAB);
    remctld_start(config, "data/conf-simple", NULL);

    plan(7);

    /* Open the connection to the site. */
    r = remctl_new();
    ok(r != NULL, "remctl_new");
    ok(remctl_open(r, "localhost", 14373, config->principal), "remctl_open");

    /* Send the no-op token. */
    tok.length = sizeof(token);
    tok.value = (char *) token;
    status = token_send_priv(r->fd, r->context, TOKEN_DATA | TOKEN_PROTOCOL,
                             &tok, 0, &major, &minor);
    if (status != TOKEN_OK)
        bail("cannot send token");

    /* Accept the remote token. */
    status = token_recv_priv(r->fd, r->context, &flags, &tok, 1024 * 64, 0,
                             &major, &minor);
    is_int(TOKEN_OK, status, "received token correctly");
    is_int(TOKEN_DATA | TOKEN_PROTOCOL, flags, "token had correct flags");
    is_int(2, tok.length, "token had correct length");
    is_int(3, ((char *) tok.value)[0], "protocol version is 3");
    is_int(MESSAGE_NOOP, ((char *) tok.value)[1], "no-op message");

    /* Close things out. */
    remctl_close(r);
    return 0;
}
コード例 #3
0
ファイル: client-v1.c プロジェクト: moretension/remctl
/*
 * Retrieve the output from the server using protocol version one and return
 * it.  This function will actually be called twice, once to retrieve the
 * output data and once to retrieve the exit status.  The old protocol
 * returned those together in one message, so we have to buffer the exit
 * status and return it on the second call.  Returns a remctl output struct on
 * success and NULL on failure.
 */
struct remctl_output *
internal_v1_output(struct remctl *r)
{
    int status, flags;
    gss_buffer_desc token;
    OM_uint32 data, major, minor, length;
    char *p;

    /*
     * First, see if we already had an output struct.  If so, this is the
     * second call and we should just return the exit status.
     */
    if (r->output != NULL && !r->ready) {
        if (r->output->type == REMCTL_OUT_STATUS)
            r->output->type = REMCTL_OUT_DONE;
        else {
            internal_output_wipe(r->output);
            r->output->type = REMCTL_OUT_STATUS;
        }
        r->output->status = r->status;
        return r->output;
    }

    /* Otherwise, we have to read the token from the server. */
    status = token_recv_priv(r->fd, r->context, &flags, &token,
                             TOKEN_MAX_LENGTH, r->timeout, &major, &minor);
    if (status != TOKEN_OK) {
        internal_token_error(r, "receiving token", status, major, minor);
        if (status == TOKEN_FAIL_EOF || status == TOKEN_FAIL_TIMEOUT) {
            gss_delete_sec_context(&minor, &r->context, GSS_C_NO_BUFFER);
            r->context = GSS_C_NO_CONTEXT;
            socket_close(r->fd);
            r->fd = INVALID_SOCKET;
            r->ready = false;
        }
        return NULL;
    }
    if (flags != TOKEN_DATA) {
        internal_set_error(r, "unexpected token from server");
        gss_release_buffer(&minor, &token);
        return NULL;
    }

    /* Extract the return code, message length, and data. */
    if (token.length < 8) {
        internal_set_error(r, "malformed result token from server");
        gss_release_buffer(&minor, &token);
        return NULL;
    }
    p = token.value;
    memcpy(&data, p, 4);
    r->status = ntohl(data);
    p += 4;
    memcpy(&data, p, 4);
    length = ntohl(data);
    p += 4;
    if (length != token.length - 8) {
        internal_set_error(r, "malformed result token from server");
        gss_release_buffer(&minor, &token);
        return NULL;
    }

    /*
     * Allocate the new output token.  We make another copy of the data,
     * unfortunately, so that we don't have to keep the token around to free
     * later.
     */
    r->output = malloc(sizeof(struct remctl_output));
    if (r->output == NULL) {
        internal_set_error(r, "cannot allocate memory: %s", strerror(errno));
        gss_release_buffer(&minor, &token);
        return NULL;
    }
    r->output->type = REMCTL_OUT_OUTPUT;
    r->output->data = malloc(length);
    if (r->output->data == NULL) {
        internal_set_error(r, "cannot allocate memory: %s", strerror(errno));
        gss_release_buffer(&minor, &token);
        return NULL;
    }
    memcpy(r->output->data, p, length);
    r->output->length = length;
    gss_release_buffer(&minor, &token);

    /*
     * We always claim everything was stdout since we have no way of knowing
     * better with protocol version one.
     */
    r->output->stream = 1;

    /*
     * We can only do one round with protocol version one, so close the
     * connection now.
     */
    gss_delete_sec_context(&minor, &r->context, GSS_C_NO_BUFFER);
    r->context = GSS_C_NO_CONTEXT;
    socket_close(r->fd);
    r->fd = INVALID_SOCKET;
    r->ready = false;
    return r->output;
}