/* * Send a command to the server using protocol v1. Returns true on success, * false on failure. */ bool internal_v1_commandv(struct remctl *r, const struct iovec *command, size_t count) { gss_buffer_desc token; size_t i; char *p; OM_uint32 data, major, minor; int status; /* Allocate room for the total message: argc, {<length><arg>}+. */ token.length = 4; for (i = 0; i < count; i++) token.length += 4 + command[i].iov_len; token.value = malloc(token.length); if (token.value == NULL) { internal_set_error(r, "cannot allocate memory: %s", strerror(errno)); return false; } /* First, the argument count. Then, each argument. */ p = token.value; data = htonl(count); memcpy(p, &data, 4); p += 4; for (i = 0; i < count; i++) { data = htonl(command[i].iov_len); memcpy(p, &data, 4); p += 4; memcpy(p, command[i].iov_base, command[i].iov_len); p += command[i].iov_len; } /* Send the result. */ status = token_send_priv(r->fd, r->context, TOKEN_DATA | TOKEN_SEND_MIC, &token, r->timeout, &major, &minor); if (status != TOKEN_OK) { internal_token_error(r, "sending token", status, major, minor); free(token.value); return false; } free(token.value); r->ready = true; return true; }
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; }
/* * Given the client struct, a buffer of data to send, and the exit status of a * command, send a protocol v1 output token back to the client. Returns true * on success and false on failure (and logs a message on failure). */ bool server_v1_send_output(struct client *client, struct evbuffer *output, int exit_status) { gss_buffer_desc token; size_t outlen; char *p; OM_uint32 tmp, major, minor; int status; /* Allocate room for the total message. */ outlen = evbuffer_get_length(output); token.length = 4 + 4 + outlen; token.value = xmalloc(token.length); /* Fill in the token. */ p = token.value; tmp = htonl(exit_status); memcpy(p, &tmp, 4); p += 4; tmp = htonl(outlen); memcpy(p, &tmp, 4); p += 4; if (evbuffer_remove(output, p, outlen) < 0) die("internal error: cannot move data from output buffer"); /* Send the token. */ status = token_send_priv(client->fd, client->context, TOKEN_DATA, &token, TIMEOUT, &major, &minor); if (status != TOKEN_OK) { warn_token("sending output token", status, major, minor); free(token.value); return false; } free(token.value); return true; }