#include "para.h"
#include "error.h"
#include "list.h"
+#include "lsu.h"
#include "sched.h"
#include "crypt.h"
#include "net.h"
if (!ct)
return;
free(ct->user);
- free(ct->config_file);
free(ct->key_file);
lls_free_parse_result(ct->lpr, CLIENT_CMD_PTR);
free(ct->challenge_hash);
}
/*
- * The preselect hook for server commands.
+ * This function asks the scheduler to monitor a file descriptor which
+ * corresponds to an active connection. The descriptor is monitored for either
+ * reading or writing, depending on the state of the connection.
*
- * The task pointer must contain a pointer to the initialized client data
- * structure as it is returned by client_open().
- *
- * This function checks the state of the connection and adds the file descriptor
- * of the connection to the read or write fd set of s accordingly.
+ * The context pointer is assumed to refer to a client task structure that was
+ * initialized earlier by client_open().
*/
static void client_pre_select(struct sched *s, void *context)
{
else if (ret > 0)
para_fd_set(ct->scc.fd, &s->wfds, &s->max_fileno);
}
- /* fallthrough */
+ __attribute__ ((fallthrough));
case CL_EXECUTING:
if (ct->btrn[0]) {
ret = btr_node_status(ct->btrn[0], 0, BTR_NT_ROOT);
return send_sb(ct, 0, command, len, SBD_COMMAND, false);
}
+static bool has_feature(const char *feature, struct client_task *ct)
+{
+ return find_arg(feature, ct->features) >= 0? true : false;
+}
+
/*
- * The post select hook for client commands.
+ * This function reads or writes to the socket file descriptor which
+ * corresponds to an established connection between the client and the server.
+ * It depends on the current state of the connection and on the readiness of
+ * the socket file descriptor which type of I/O is going to be performed.
+ * Besides the initial handshake and authentication, the function sends the
+ * server command and receives the output from the server, if any.
*
- * Depending on the current state of the connection and the status of the read
- * and write fd sets of s, this function performs the necessary steps to
- * authenticate the connection, to send the command given by t->private_data
- * and to receive para_server's output, if any.
+ * The context pointer refers to a client task structure that was initialized
+ * earlier by client_open().
*/
static int client_post_select(struct sched *s, void *context)
{
ct->status = CL_RECEIVED_WELCOME;
return 0;
case CL_RECEIVED_WELCOME: /* send auth command */
+ {
+ /*
+ * Use sha256 iff the server announced the feature. After 0.7.0
+ * we may request and use the feature unconditionally. After
+ * 0.8.0 we no longer need to request the feature.
+ */
+ bool has_sha256;
if (!FD_ISSET(ct->scc.fd, &s->wfds))
return 0;
- sprintf(buf, AUTH_REQUEST_MSG "%s sideband,aes_ctr128",
- ct->user);
+ has_sha256 = has_feature("sha256", ct);
+ sprintf(buf, AUTH_REQUEST_MSG "%s%s", ct->user, has_sha256?
+ " sha256" : "");
PARA_INFO_LOG("--> %s\n", buf);
ret = write_buffer(ct->scc.fd, buf);
if (ret < 0)
goto out;
ct->status = CL_SENT_AUTH;
return 0;
+ }
case CL_SENT_AUTH:
/*
* Receive challenge and session keys, decrypt the challenge and
}
n = sbb.iov.iov_len;
PARA_INFO_LOG("<-- [challenge] (%zu bytes)\n", n);
- ret = priv_decrypt(ct->key_file, crypt_buf,
+ ret = apc_priv_decrypt(ct->key_file, crypt_buf,
sbb.iov.iov_base, n);
free(sbb.iov.iov_base);
if (ret < 0)
goto out;
- ct->challenge_hash = para_malloc(HASH_SIZE);
- hash_function((char *)crypt_buf, CHALLENGE_SIZE, ct->challenge_hash);
- ct->scc.send = sc_new(crypt_buf + CHALLENGE_SIZE, SESSION_KEY_LEN);
- ct->scc.recv = sc_new(crypt_buf + CHALLENGE_SIZE + SESSION_KEY_LEN,
+ ct->challenge_hash = para_malloc(HASH2_SIZE);
+
+ if (has_feature("sha256", ct)) {
+ hash2_function((char *)crypt_buf, APC_CHALLENGE_SIZE, ct->challenge_hash);
+ hash2_to_asc(ct->challenge_hash, buf);
+ } else {
+ hash_function((char *)crypt_buf, APC_CHALLENGE_SIZE, ct->challenge_hash);
+ hash_to_asc(ct->challenge_hash, buf);
+ }
+ ct->scc.send = sc_new(crypt_buf + APC_CHALLENGE_SIZE, SESSION_KEY_LEN);
+ ct->scc.recv = sc_new(crypt_buf + APC_CHALLENGE_SIZE + SESSION_KEY_LEN,
SESSION_KEY_LEN);
- hash_to_asc(ct->challenge_hash, buf);
PARA_INFO_LOG("--> %s\n", buf);
ct->status = CL_RECEIVED_CHALLENGE;
return 0;
}
case CL_RECEIVED_CHALLENGE:
- ret = send_sb(ct, 0, ct->challenge_hash, HASH_SIZE,
- SBD_CHALLENGE_RESPONSE, false);
+ if (has_feature("sha256", ct))
+ ret = send_sb(ct, 0, ct->challenge_hash, HASH2_SIZE,
+ SBD_CHALLENGE_RESPONSE, false);
+ else
+ ret = send_sb(ct, 0, ct->challenge_hash, HASH_SIZE,
+ SBD_CHALLENGE_RESPONSE, false);
if (ret != 0)
ct->challenge_hash = NULL;
if (ret <= 0)
btr_consume(ct->btrn[1], sz);
}
}
- /* fall through */
+ __attribute__ ((fallthrough));
case CL_EXECUTING:
if (ct->btrn[0]) {
ret = btr_node_status(ct->btrn[0], 0, BTR_NT_ROOT);
int *loglevel)
{
const struct lls_command *cmd = CLIENT_CMD_PTR;
- void *map;
- size_t sz;
struct lls_parse_result *lpr;
int ret, ll;
struct client_task *ct;
- char *cf = NULL, *kf = NULL, *user, *errctx, *home = para_homedir();
+ char *kf = NULL, *user, *errctx, *home = para_homedir();
ret = lls(lls_parse(argc, argv, cmd, &lpr, &errctx));
if (ret < 0)
goto out;
- ll = CLIENT_OPT_UINT32_VAL(LOGLEVEL, lpr);
version_handle_flag("client", CLIENT_OPT_GIVEN(VERSION, lpr));
handle_help_flag(lpr);
- if (CLIENT_OPT_GIVEN(CONFIG_FILE, lpr))
- cf = para_strdup(CLIENT_OPT_STRING_VAL(CONFIG_FILE, lpr));
- else
- cf = make_message("%s/.paraslash/client.conf", home);
- ret = mmap_full_file(cf, O_RDONLY, &map, &sz, NULL);
- if (ret < 0) {
- if (ret != -E_EMPTY && ret != -ERRNO_TO_PARA_ERROR(ENOENT))
- goto out;
- if (ret == -ERRNO_TO_PARA_ERROR(ENOENT) &&
- CLIENT_OPT_GIVEN(CONFIG_FILE, lpr))
- goto out;
- } else {
- int cf_argc;
- char **cf_argv;
- struct lls_parse_result *cf_lpr, *merged_lpr;
- ret = lls(lls_convert_config(map, sz, NULL, &cf_argv, &errctx));
- para_munmap(map, sz);
- if (ret < 0)
- goto out;
- cf_argc = ret;
- ret = lls(lls_parse(cf_argc, cf_argv, cmd, &cf_lpr, &errctx));
- lls_free_argv(cf_argv);
- if (ret < 0)
- goto out;
- ret = lls(lls_merge(lpr, cf_lpr, cmd, &merged_lpr,
- &errctx));
- lls_free_parse_result(cf_lpr, cmd);
- if (ret < 0)
- goto out;
- lls_free_parse_result(lpr, cmd);
- lpr = merged_lpr;
- }
+ ret = lsu_merge_config_file_options(CLIENT_OPT_STRING_VAL(CONFIG_FILE, lpr),
+ "client.conf", &lpr, cmd, client_suite, 0U /* default flags */);
+ if (ret < 0)
+ goto out;
/* success */
+ ll = CLIENT_OPT_UINT32_VAL(LOGLEVEL, lpr);
+ if (loglevel)
+ *loglevel = ll;
user = CLIENT_OPT_GIVEN(USER, lpr)?
para_strdup(CLIENT_OPT_STRING_VAL(USER, lpr)) : para_logname();
}
}
PARA_INFO_LOG("user: %s\n", user);
- PARA_INFO_LOG("config file: %s\n", cf);
PARA_INFO_LOG("key file: %s\n", kf);
PARA_INFO_LOG("loglevel: %d\n", ll);
ct = para_calloc(sizeof(*ct));
ct->scc.fd = -1;
ct->lpr = lpr;
ct->key_file = kf;
- ct->config_file = cf;
ct->user = user;
*ct_ptr = ct;
- if (loglevel)
- *loglevel = ll;
ret = lls_num_inputs(lpr);
out:
free(home);
if (errctx)
PARA_ERROR_LOG("%s\n", errctx);
free(errctx);
- PARA_ERROR_LOG("%s\n", para_strerror(-ret));
lls_free_parse_result(lpr, cmd);
- free(cf);
free(kf);
*ct_ptr = NULL;
}