Exemple #1
0
void
_sasl_encode_inplace(sasl_conn_t *ctx, struct hdfs_heap_buf *b)
{
	const char *out;
	unsigned outlen;
	int r;

	r = sasl_encode(ctx, b->buf, b->used, &out, &outlen);
	if (r != SASL_OK) {
		fprintf(stderr, "sasl_encode: %s\n",
		    sasl_errstring(r, NULL, NULL));
		abort();
	}

	free(b->buf);
	b->buf = malloc(4 + outlen);
	ASSERT(b->buf);

	// copy in length-prefixed encoded bits
	_be32enc(b->buf, outlen);
	memcpy(b->buf + 4, out, outlen);
	b->used = b->size = 4 + outlen;
}
Exemple #2
0
EXPORT_SYM const char *
hdfs_namenode_authenticate_full(struct hdfs_namenode *n, const char *username,
	const char *real_user)
{
	const char *error = NULL;
	struct hdfs_object *header;
	struct hdfs_heap_buf hbuf = { 0 };
	char *inh = NULL, preamble[12];
	size_t preamble_len;

	_lock(&n->nn_lock);
	ASSERT(!n->nn_authed);
	ASSERT(n->nn_sock != -1);

	memset(preamble, 0, sizeof(preamble));
	if (n->nn_proto == HDFS_NN_v1) {
		sprintf(preamble, "hrpc\x04%c",
		    (n->nn_kerb == HDFS_NO_KERB)? 0x50 : 0x51);
		preamble_len = 6;

		header = hdfs_authheader_new_ext(n->nn_proto, username,
		    real_user, HDFS_NO_KERB);
	} else if (n->nn_proto == HDFS_NN_v2) {
		/* HDFSv2 has used both version 7 (2.0.0-2.0.2) and 8 (2.0.3+). */
		sprintf(preamble, "hrpc%c%c", 8 /* XXX Configurable? */,
		    (n->nn_kerb == HDFS_NO_KERB)? 0x50 : 0x51);
		/* There is a zero at the end: */
		preamble_len = 7;

		header = hdfs_authheader_new_ext(n->nn_proto, username,
		    real_user, n->nn_kerb);
	} else if (n->nn_proto == HDFS_NN_v2_2) {
		memcpy(preamble, "hrpc\x09", 5);
		preamble[5] = 0;
		preamble[6] = (n->nn_kerb == HDFS_NO_KERB)? 0 : -33;
		preamble_len = 7;

		header = hdfs_authheader_new_ext(n->nn_proto, username,
		    real_user, n->nn_kerb);
		_authheader_set_clientid(header, n->nn_client_id);
	} else {
		ASSERT(false);
	}

	// Serialize the connection header object (I am speaking ClientProtocol
	// and this is my username)
	hdfs_object_serialize(&hbuf, header);
	hdfs_object_free(header);

	if (n->nn_kerb == HDFS_NO_KERB) {
		// Prefix the header object with the protocol preamble
		hbuf.buf = realloc(hbuf.buf, hbuf.size + preamble_len);
		ASSERT(hbuf.buf);
		memmove(hbuf.buf + preamble_len, hbuf.buf, hbuf.used);
		memcpy(hbuf.buf, preamble, preamble_len);
		hbuf.used += preamble_len;
		hbuf.size += preamble_len;
	} else {
		/*
		 * XXX This is probably totally wrong for HDFSv2+. They start
		 * using protobufs at this point to wrap the SASL packets.
		 *
		 * To be fair, it's probably broken for HDFSv1 too :). I need
		 * to find a kerberized HDFS to test against.
		 */
		int r;
		sasl_interact_t *interactions = NULL;
		const char *out, *mechusing;
		unsigned outlen;
		struct iovec iov[3];
		uint32_t inlen;
		const uint32_t SWITCH_TO_SIMPLE_AUTH = (uint32_t)-1;

		uint8_t in[4], zero[4] = { 0 };

		do {
			r = sasl_client_start(n->nn_sasl_ctx, "GSSAPI",
			    &interactions, &out, &outlen, &mechusing);

			if (r == SASL_INTERACT)
				_sasl_interacts(interactions);
		} while (r == SASL_INTERACT);

		if (r != SASL_CONTINUE) {
			error = sasl_errstring(r, NULL, NULL);
			goto out;
		}

		// Send prefix, first auth token
		_be32enc(in, outlen);
		iov[0].iov_base = preamble;
		iov[0].iov_len = preamble_len;
		iov[1].iov_base = in;
		iov[1].iov_len = 4;
		iov[2].iov_base = __DECONST(void *, out);
		iov[2].iov_len = outlen;

		error = _writev_all(n->nn_sock, iov, 3);
		if (error)
			goto out;

		do {
			// read success / error status
			error = _read_all(n->nn_sock, in, 4);
			if (error)
				goto out;

			if (memcmp(in, zero, 4)) {
				// error. exception will be next on the wire,
				// but let's skip it.
				error = "Got error from server, bailing";
				goto out;
			}

			// read token len
			error = _read_all(n->nn_sock, in, 4);
			if (error)
				goto out;
			inlen = _be32dec(in);

			if (inlen == SWITCH_TO_SIMPLE_AUTH) {
				if (n->nn_kerb == HDFS_REQUIRE_KERB) {
					error = "Server tried to drop kerberos but "
					    "client requires it";
					goto out;
				}
				goto send_header;
			}

			// read token
			if (inh)
				free(inh);
			inh = NULL;
			if (inlen > 0) {
				inh = malloc(inlen);
				ASSERT(inh);
				error = _read_all(n->nn_sock, inh, inlen);
				if (error)
					goto out;
			}

			out = NULL;
			outlen = 0;
			r = sasl_client_step(n->nn_sasl_ctx, inh,
			    inlen, &interactions, &out, &outlen);

			if (r == SASL_INTERACT)
				_sasl_interacts(interactions);

			if (r == SASL_CONTINUE ||
			    (r == SASL_OK && out != NULL)) {
				_be32enc(in, outlen);
				iov[0].iov_base = in;
				iov[0].iov_len = 4;
				iov[1].iov_base = __DECONST(void *, out);
				iov[1].iov_len = outlen;

				error = _writev_all(n->nn_sock, iov, 2);
				if (error)
					goto out;
			}
		} while (r == SASL_INTERACT || r == SASL_CONTINUE);

		if (r != SASL_OK) {
			error = sasl_errstring(r, NULL, NULL);
			goto out;
		}

		// sasl connection established
		n->nn_sasl_ssf = _getssf(n->nn_sasl_ctx);
send_header:
		if (n->nn_sasl_ssf > 0)
			_sasl_encode_inplace(n->nn_sasl_ctx, &hbuf);
	}

	// send auth header
	error = _write_all(n->nn_sock, hbuf.buf, hbuf.used);
	n->nn_authed = true;

out:
	if (inh)
		free(inh);
	_unlock(&n->nn_lock);
	free(hbuf.buf);

	return error;
}