Just committed... commit 8ee54c1631af713bc11426400a405d948ce71ffc Author: Jeff Garzik <jeff@xxxxxxxxxx> Date: Tue Nov 10 02:56:17 2009 -0500 Add LOGIN request, and stop sending username in each message. The per-request message header shrinks by 64 bytes. This is an incompatible network protocol change, but the programming API stays unchanged. Also, libchunkdc: better validation of stc_new() arguments Signed-off-by: Jeff Garzik <jgarzik@xxxxxxxxxx> diff --git a/include/chunk_msg.h b/include/chunk_msg.h index 25e1f9b..90272ca 100644 --- a/include/chunk_msg.h +++ b/include/chunk_msg.h @@ -20,6 +20,7 @@ enum chunksrv_ops { CHO_PUT = 3, CHO_DEL = 4, CHO_LIST = 5, + CHO_LOGIN = 6, }; enum chunk_errcode { @@ -44,7 +45,6 @@ struct chunksrv_req { uint16_t key_len; uint32_t nonce; /* random number, to stir checksum */ uint64_t data_len; /* len of addn'l data */ - char user[CHD_USER_SZ]; /* username */ char sig[CHD_SIG_SZ]; /* HMAC signature */ /* variable-length key */ diff --git a/lib/chunkdc.c b/lib/chunkdc.c index efbf77b..1597e91 100644 --- a/lib/chunkdc.c +++ b/lib/chunkdc.c @@ -49,7 +49,6 @@ static void req_init(struct st_client *stc, struct chunksrv_req *req) memset(req, 0, sizeof(*req)); memcpy(req->magic, CHUNKD_MAGIC, CHD_MAGIC_SZ); req->nonce = rand(); - strcpy(req->user, stc->user); } static void req_set_key(struct chunksrv_req *req, const void *key, @@ -138,6 +137,41 @@ void stc_free(struct st_client *stc) free(stc); } +static bool stc_login(struct st_client *stc) +{ + struct chunksrv_resp resp; + struct chunksrv_req *req = (struct chunksrv_req *) stc->req_buf; + + if (stc->verbose) + fprintf(stderr, "libstc: LOGIN\n"); + + /* initialize request; username is sent as key/key_len */ + req_init(stc, req); + req->op = CHO_LOGIN; + req_set_key(req, stc->user, strlen(stc->user) + 1); + + /* sign request */ + chreq_sign(req, stc->key, req->sig); + + /* write request */ + if (!net_write(stc, req, req_len(req))) + return false; + + /* read response header */ + if (!net_read(stc, &resp, sizeof(resp))) + return false; + + /* check response code */ + if (resp.resp_code != che_Success) { + if (stc->verbose) + fprintf(stderr, "LOGIN failed, resp code: %d\n", + resp.resp_code); + return false; + } + + return true; +} + struct st_client *stc_new(const char *service_host, int port, const char *user, const char *secret_key, bool use_ssl) @@ -147,6 +181,12 @@ struct st_client *stc_new(const char *service_host, int port, int rc, fd = -1, on = 1; char port_str[32]; + if (!service_host || !*service_host || + port < 1 || port > 65535 || + !user || !*user || + !secret_key || !*secret_key) + return NULL; + sprintf(port_str, "%d", port); memset(&hints, 0, sizeof(hints)); @@ -211,6 +251,9 @@ struct st_client *stc_new(const char *service_host, int port, goto err_out_ssl; } + if (!stc_login(stc)) + goto err_out_ssl; + return stc; err_out_ssl: diff --git a/server/chunkd.h b/server/chunkd.h index e7e2115..d6b37c6 100644 --- a/server/chunkd.h +++ b/server/chunkd.h @@ -76,6 +76,8 @@ struct client { char addr_host[64]; /* ASCII version of inet addr */ int fd; /* socket */ + char user[CHD_USER_SZ + 1]; + SSL *ssl; bool read_want_write; bool write_want_read; diff --git a/server/object.c b/server/object.c index 5ca7a19..23b0aa9 100644 --- a/server/object.c +++ b/server/object.c @@ -30,7 +30,7 @@ bool object_del(struct client *cli) resp_init_req(resp, &cli->creq); - rcb = fs_obj_delete(cli->creq.user, cli->key, cli->key_len, &err); + rcb = fs_obj_delete(cli->user, cli->key, cli->key_len, &err); if (!rcb) return cli_err(cli, err, true); @@ -189,7 +189,7 @@ bool cli_evt_data_in(struct client *cli, unsigned int events) bool object_put(struct client *cli) { - const char *user = cli->creq.user; + const char *user = cli->user; uint64_t content_len = le64_to_cpu(cli->creq.data_len); enum chunk_errcode err; @@ -286,7 +286,7 @@ bool object_get(struct client *cli, bool want_body) resp_init_req(&get_resp->resp, &cli->creq); - cli->in_obj = obj = fs_obj_open(cli->creq.user, cli->key, + cli->in_obj = obj = fs_obj_open(cli->user, cli->key, cli->key_len, &err); if (!obj) { free(get_resp); diff --git a/server/server.c b/server/server.c index 76c007f..2d9095f 100644 --- a/server/server.c +++ b/server/server.c @@ -728,7 +728,7 @@ static bool volume_list(struct client *cli) bool rcb; GList *res = NULL; - res = fs_list_objs(cli->creq.user); + res = fs_list_objs(cli->user); s = g_markup_printf_escaped( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n" @@ -785,7 +785,7 @@ static bool volume_list(struct client *cli) } static bool authcheck(const struct chunksrv_req *req, const void *key, - size_t key_len) + size_t key_len, const char *secret_key) { char req_buf[sizeof(struct chunksrv_req) + CHD_KEY_SZ]; struct chunksrv_req *tmpreq = (struct chunksrv_req *) req_buf; @@ -795,12 +795,39 @@ static bool authcheck(const struct chunksrv_req *req, const void *key, memcpy((tmpreq + 1), key, key_len); memset(tmpreq->sig, 0, sizeof(tmpreq->sig)); + chreq_sign(tmpreq, secret_key, hmac); + + return strcmp(req->sig, hmac) ? false : true; +} + +static bool login_user(struct client *cli) +{ + struct chunksrv_req *req = &cli->creq; + enum chunk_errcode err; + + /* validate username length */ + if (cli->key_len < 1 || cli->key_len > CHD_USER_SZ) { + err = che_InvalidArgument; + cli->state = evt_dispose; + goto err_out; + } + + memset(cli->user, 0, sizeof(cli->user)); + memcpy(cli->user, cli->key, cli->key_len); + /* for lack of a better authentication scheme, we * supply the username as the secret key */ - chreq_sign(tmpreq, req->user, hmac); + if (!authcheck(req, cli->key, cli->key_len, cli->user)) { + err = che_SignatureDoesNotMatch; + cli->state = evt_dispose; + goto err_out; + } - return strcmp(req->sig, hmac) ? false : true; + return cli_err(cli, che_Success, true); + +err_out: + return cli_err(cli, err, false); } static bool valid_req_hdr(const struct chunksrv_req *req) @@ -810,10 +837,6 @@ static bool valid_req_hdr(const struct chunksrv_req *req) if (memcmp(req->magic, CHUNKD_MAGIC, CHD_MAGIC_SZ)) return false; - len = strnlen(req->user, sizeof(req->user)); - if (len < 1 || len == sizeof(req->user)) - return false; - len = strnlen(req->sig, sizeof(req->sig)); if (len < 1 || len == sizeof(req->sig)) return false; @@ -830,6 +853,7 @@ static const char *op2str(enum chunksrv_ops op) case CHO_PUT: return "CHO_PUT"; case CHO_DEL: return "CHO_DEL"; case CHO_LIST: return "CHO_LIST"; + case CHO_LOGIN: return "CHO_LOGIN"; default: return "BUG/UNKNOWN!"; @@ -844,6 +868,7 @@ static bool cli_evt_exec_req(struct client *cli, unsigned int events) struct chunksrv_req *req = &cli->creq; bool rcb; enum chunk_errcode err; + bool logged_in = (cli->user[0] != 0); /* validate request header */ if (!valid_req_hdr(req)) { @@ -851,27 +876,41 @@ static bool cli_evt_exec_req(struct client *cli, unsigned int events) goto err_out; } + if (debugging) + applog(LOG_DEBUG, "REQ(op %s, key %s (%u), user %s) " + "seq %x len %lld login %s", + op2str(req->op), + cli->key, + cli->key_len, + cli->user, + req->nonce, + (long long) le64_to_cpu(req->data_len), + logged_in ? "Y" : "N"); + /* check authentication */ - if (!authcheck(req, cli->key, cli->key_len)) { + /* for lack of a better authentication scheme, we + * supply the username as the secret key + */ + if (logged_in && + !authcheck(req, cli->key, cli->key_len, cli->user)) { err = che_SignatureDoesNotMatch; goto err_out; } cli->state = evt_recycle; - if (debugging) - applog(LOG_DEBUG, "REQ(op %s, key %s (%u), user %s) seq %x len %lld", - op2str(req->op), - cli->key, - cli->key_len, - req->user, - req->nonce, - (long long) le64_to_cpu(req->data_len)); + if (G_UNLIKELY((!logged_in) && (req->op != CHO_LOGIN))) { + cli->state = evt_dispose; + return true; + } /* * operations on objects */ switch (req->op) { + case CHO_LOGIN: + rcb = login_user(cli); + break; case CHO_NOP: rcb = cli_err(cli, che_Success, true); break; -- To unsubscribe from this list: send the line "unsubscribe hail-devel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html