[PATCH] chunkd: add LOGIN message, don't send username in each request

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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

[Index of Archives]     [Fedora Clound]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux