Incompatible network protocol change just committed... commit 6fb485cbffcf61d73b0cfe7effbf88c9e0b48377 Author: Jeff Garzik <jeff@xxxxxxxxxx> Date: Thu Nov 5 00:06:16 2009 -0500 Change protocol to permit arbitrary binary keys, up to 1K in size. Also, - remove several unused struct members from struct chunksrv_resp. - improve client disconnect logging Signed-off-by: Jeff Garzik <jgarzik@xxxxxxxxxx> diff --git a/include/chunk_msg.h b/include/chunk_msg.h index 4222f27..0efe7a3 100644 --- a/include/chunk_msg.h +++ b/include/chunk_msg.h @@ -8,7 +8,7 @@ enum { CHD_MAGIC_SZ = 8, CHD_USER_SZ = 64, - CHD_KEY_SZ = 64, + CHD_KEY_SZ = 1024, CHD_CSUM_SZ = 64, CHD_SIG_SZ = 64, }; @@ -38,23 +38,22 @@ enum errcode { struct chunksrv_req { uint8_t magic[CHD_MAGIC_SZ]; /* CHUNKD_MAGIC */ uint8_t op; /* CHO_xxx */ - uint8_t rsv1[3]; + uint8_t rsv1[1]; + 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 key[CHD_KEY_SZ]; /* object id */ char sig[CHD_SIG_SZ]; /* HMAC signature */ + + /* variable-length key */ }; struct chunksrv_resp { uint8_t magic[CHD_MAGIC_SZ]; /* CHUNKD_MAGIC */ - uint8_t op; /* CHO_xxx */ uint8_t resp_code; /* errcode's */ - uint8_t rsv1[2]; - uint32_t nonce; /* random number, to stir checksum */ + uint8_t rsv1[3]; + uint32_t nonce; /* txn id, copied from request */ uint64_t data_len; /* len of addn'l data */ - char user[CHD_USER_SZ]; /* username */ - char key[CHD_KEY_SZ]; /* object id */ char checksum[CHD_CSUM_SZ]; /* SHA1 checksum */ }; diff --git a/include/chunkc.h b/include/chunkc.h index d815ce0..1cc8cc7 100644 --- a/include/chunkc.h +++ b/include/chunkc.h @@ -32,7 +32,7 @@ struct st_client { SSL_CTX *ssl_ctx; SSL *ssl; - char req_buf[sizeof(struct chunksrv_req)]; + char req_buf[sizeof(struct chunksrv_req) + CHD_KEY_SZ]; }; extern void stc_free(struct st_client *stc); diff --git a/lib/chunkdc.c b/lib/chunkdc.c index a2df1e0..73731d4 100644 --- a/lib/chunkdc.c +++ b/lib/chunkdc.c @@ -45,12 +45,10 @@ static void req_init(struct st_client *stc, struct chunksrv_req *req) } static void req_set_key(struct chunksrv_req *req, const void *key, - size_t key_len) + uint16_t key_len) { - /* length must include nul, and already be checked for range - * validity - */ - memcpy(req->key, key, key_len); + req->key_len = GUINT16_TO_LE(key_len); + memcpy((req + 1), key, key_len); } static bool net_read(struct st_client *stc, void *data, size_t datalen) diff --git a/lib/chunksrv.c b/lib/chunksrv.c index d6482b2..cd8a093 100644 --- a/lib/chunksrv.c +++ b/lib/chunksrv.c @@ -7,7 +7,11 @@ size_t req_len(const struct chunksrv_req *req) { - return sizeof(*req); + size_t len; + + len = sizeof(struct chunksrv_req) + GUINT16_FROM_LE(req->key_len); + + return len; } void chreq_sign(struct chunksrv_req *req, const char *key, char *b64hmac_out) @@ -17,7 +21,7 @@ void chreq_sign(struct chunksrv_req *req, const char *key, char *b64hmac_out) int save = 0, state = 0, b64_len; const void *p = req; - HMAC(EVP_sha1(), key, strlen(key), p, sizeof(*req), md, &len); + HMAC(EVP_sha1(), key, strlen(key), p, req_len(req), md, &len); b64_len = g_base64_encode_step(md, len, FALSE, b64hmac_out, &state, &save); diff --git a/server/chunkd.h b/server/chunkd.h index 8e666e7..d56e5da 100644 --- a/server/chunkd.h +++ b/server/chunkd.h @@ -60,7 +60,8 @@ struct client_write { /* internal client socket state */ enum client_state { - evt_read_req, /* read request line */ + evt_read_fixed, /* read fixed-len rec */ + evt_read_var, /* read variable-len rec */ evt_exec_req, /* execute request */ evt_data_in, /* request's content */ evt_dispose, /* dispose of client */ @@ -85,6 +86,7 @@ struct client { struct chunksrv_req creq; unsigned int req_used; /* amount of req_buf in use */ void *req_ptr; /* start of unexamined data */ + uint16_t key_len; char *hdr_start; /* current hdr start */ char *hdr_end; /* current hdr end (so far) */ @@ -103,6 +105,7 @@ struct client { char netbuf[CLI_DATA_BUF_SZ]; char netbuf_out[CLI_DATA_BUF_SZ]; + char key[CHD_KEY_SZ]; }; struct backend_obj { diff --git a/server/object.c b/server/object.c index 0792b66..62a1acb 100644 --- a/server/object.c +++ b/server/object.c @@ -17,7 +17,6 @@ static bool object_get_more(struct client *cli, struct client_write *wr, bool object_del(struct client *cli) { - const char *obj_key = cli->creq.key; int rc; enum errcode err = InternalError; bool rcb; @@ -31,8 +30,7 @@ bool object_del(struct client *cli) resp_init_req(resp, &cli->creq); - rcb = fs_obj_delete(cli->creq.user, obj_key, - strnlen(obj_key, CHD_KEY_SZ), &err); + rcb = fs_obj_delete(cli->creq.user, cli->key, cli->key_len, &err); if (!rcb) return cli_err(cli, err, true); @@ -192,14 +190,13 @@ 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 *key = cli->creq.key; uint64_t content_len = le64_to_cpu(cli->creq.data_len); enum errcode err; if (!user) return cli_err(cli, AccessDenied, true); - cli->out_bo = fs_obj_new(key, strnlen(key, CHD_KEY_SZ), &err); + cli->out_bo = fs_obj_new(cli->key, cli->key_len, &err); if (!cli->out_bo) return cli_err(cli, err, true); @@ -277,7 +274,6 @@ err_out_buf: bool object_get(struct client *cli, bool want_body) { - const char *obj_key = cli->creq.key; int rc; enum errcode err = InternalError; struct backend_obj *obj; @@ -291,8 +287,8 @@ 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, obj_key, - strnlen(obj_key, CHD_KEY_SZ), &err); + cli->in_obj = obj = fs_obj_open(cli->creq.user, cli->key, + cli->key_len, &err); if (!obj) { free(get_resp); return cli_err(cli, err, true); diff --git a/server/server.c b/server/server.c index b2911b2..0fc138e 100644 --- a/server/server.c +++ b/server/server.c @@ -274,11 +274,8 @@ void resp_init_req(struct chunksrv_resp *resp, { memset(resp, 0, sizeof(*resp)); memcpy(resp->magic, req->magic, CHD_MAGIC_SZ); - resp->op = req->op; resp->nonce = req->nonce; resp->data_len = req->data_len; - strncpy(resp->user, req->user, CHD_USER_SZ); - strncpy(resp->key, req->key, CHD_KEY_SZ); } static bool cli_write_free(struct client *cli, struct client_write *tmp, @@ -316,6 +313,8 @@ static void cli_write_free_all(struct client *cli) static void cli_free(struct client *cli) { + applog(LOG_INFO, "client %s disconnected", cli->addr_host); + cli_write_free_all(cli); cli_out_end(cli); @@ -325,8 +324,10 @@ static void cli_free(struct client *cli) if (cli->fd >= 0) { if (cli->ssl) SSL_shutdown(cli->ssl); - srv_poll_del(cli->fd); - close(cli->fd); + if (!srv_poll_del(cli->fd)) + applog(LOG_ERR, "TCP cli poll del failed"); + if (close(cli->fd) < 0) + syslogerr("close(2) TCP client socket"); } if (debugging) @@ -356,7 +357,7 @@ static struct client *cli_alloc(bool use_ssl) } } - cli->state = evt_read_req; + cli->state = evt_read_fixed; INIT_LIST_HEAD(&cli->write_q); cli->req_ptr = &cli->creq; @@ -378,7 +379,7 @@ static bool cli_evt_recycle(struct client *cli, unsigned int events) { cli->req_ptr = &cli->creq; cli->req_used = 0; - cli->state = evt_read_req; + cli->state = evt_read_fixed; return true; } @@ -793,18 +794,21 @@ static bool volume_list(struct client *cli) return rcb; } -static bool authcheck(const struct chunksrv_req *req) +static bool authcheck(const struct chunksrv_req *req, const void *key, + size_t key_len) { - struct chunksrv_req tmpreq; + char req_buf[sizeof(struct chunksrv_req) + CHD_KEY_SZ]; + struct chunksrv_req *tmpreq = (struct chunksrv_req *) req_buf; char hmac[64]; - memcpy(&tmpreq, req, sizeof(tmpreq)); - memset(&tmpreq.sig, 0, sizeof(tmpreq.sig)); + memcpy(tmpreq, req, sizeof(*req)); + memcpy((tmpreq + 1), key, key_len); + memset(tmpreq->sig, 0, sizeof(tmpreq->sig)); /* for lack of a better authentication scheme, we * supply the username as the secret key */ - chreq_sign(&tmpreq, req->user, hmac); + chreq_sign(tmpreq, req->user, hmac); return strcmp(req->sig, hmac) ? false : true; } @@ -820,10 +824,6 @@ static bool valid_req_hdr(const struct chunksrv_req *req) if (len < 1 || len == sizeof(req->user)) return false; - len = strnlen(req->key, sizeof(req->key)); - if (len == sizeof(req->key)) - return false; - len = strnlen(req->sig, sizeof(req->sig)); if (len < 1 || len == sizeof(req->sig)) return false; @@ -862,7 +862,7 @@ static bool cli_evt_exec_req(struct client *cli, unsigned int events) } /* check authentication */ - if (!authcheck(req)) { + if (!authcheck(req, cli->key, cli->key_len)) { err = SignatureDoesNotMatch; goto err_out; } @@ -870,9 +870,10 @@ static bool cli_evt_exec_req(struct client *cli, unsigned int events) cli->state = evt_recycle; if (debugging) - applog(LOG_DEBUG, "REQ(op %s, key %s, user %s) seq %x len %lld", + applog(LOG_DEBUG, "REQ(op %s, key %s (%u), user %s) seq %x len %lld", op2str(req->op), - req->key, + cli->key, + cli->key_len, req->user, req->nonce, (long long) le64_to_cpu(req->data_len)); @@ -912,7 +913,7 @@ err_out: goto out; } -static bool cli_evt_read_req(struct client *cli, unsigned int events) +static bool cli_evt_read_fixed(struct client *cli, unsigned int events) { int rc = cli_read_data(cli, cli->req_ptr, sizeof(cli->creq) - cli->req_used); @@ -928,6 +929,38 @@ static bool cli_evt_read_req(struct client *cli, unsigned int events) if (cli->req_used < sizeof(struct chunksrv_req)) return false; + cli->key_len = GUINT16_FROM_LE(cli->creq.key_len); + + /* if no key, skip to execute-request state */ + if (cli->key_len == 0) { + cli->state = evt_exec_req; + return true; + } + + /* otherwise, go to read-variable-len-record state */ + cli->req_ptr = &cli->key; + cli->req_used = 0; + cli->state = evt_read_var; + + return true; +} + +static bool cli_evt_read_var(struct client *cli, unsigned int events) +{ + int rc = cli_read_data(cli, cli->req_ptr, + cli->key_len - cli->req_used); + if (rc < 0) { + cli->state = evt_dispose; + return true; + } + + cli->req_ptr += rc; + cli->req_used += rc; + + /* poll for more, if variable-length record not yet received */ + if (cli->req_used < cli->key_len) + return false; + cli->state = evt_exec_req; return true; @@ -939,7 +972,7 @@ static bool cli_evt_ssl_accept(struct client *cli, unsigned int events) rc = SSL_accept(cli->ssl); if (rc > 0) { - cli->state = evt_read_req; + cli->state = evt_read_fixed; return true; } @@ -961,7 +994,8 @@ out: } static cli_evt_func state_funcs[] = { - [evt_read_req] = cli_evt_read_req, + [evt_read_fixed] = cli_evt_read_fixed, + [evt_read_var] = cli_evt_read_var, [evt_exec_req] = cli_evt_exec_req, [evt_data_in] = cli_evt_data_in, [evt_dispose] = cli_evt_dispose, -- 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