Hello,

reposting the patches so you can take another look.

===

iscsi implementation is missing base64 encoding support. At least
StarWind uses it for CHAP and hence fails with gpxe.

Patches tested by a user who originally reported the problem and myself.

base64 +300
iscsi +63
TOTAL: +363

http://git.etherboot.org/?p=people/peper/gpxe.git;a=shortlog;h=refs/heads/base64
http://github.com/peper/gpxe-peper/compare/master...base64

-- 
Best Regards
Piotr Jaroszyński
From c61e33703253d4ccd5510e4c2b4fc6bac44b87e3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Piotr=20Jaroszy=C5=84ski?= <[email protected]>
Date: Sat, 27 Mar 2010 02:10:34 +0100
Subject: [PATCH 1/2] [base64] Add decoding support.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Piotr Jaroszyński <[email protected]>
---
 src/core/base64.c         |   70 +++++++++++++++++++++++++++++++++++++++++++++
 src/include/gpxe/base64.h |   12 ++++++++
 2 files changed, 82 insertions(+), 0 deletions(-)

diff --git a/src/core/base64.c b/src/core/base64.c
index 5619ef7..3c0d354 100644
--- a/src/core/base64.c
+++ b/src/core/base64.c
@@ -66,3 +66,73 @@ void base64_encode ( const char *raw, char *encoded ) {
 	DBG ( "Base64-encoded \"%s\" as \"%s\"\n", raw, encoded );
 	assert ( strlen ( encoded ) == base64_encoded_len ( strlen ( raw ) ) );
 }
+
+static const char base64d[80] =
+    "\x3e\x80\x80\x80\x3f\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x80"
+//     +  (,) (-) (.)  /   0   1   2   3   4   5   6   7   8   9  (:)
+    "\x80\x80\xc0\x80\x80\x80\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09"
+//    (;) (<)  =  (>) (?) (@)  A   B   C   D   E   F   G   H   I   J
+    "\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19"
+//     K   L   M   N   O   P   Q   R   S   T   U   V   W   X   Y   Z
+    "\x80\x80\x80\x80\x80\x80\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23"
+//    ([) (\) (]) (^) (_) (`)  a   b   c   d   e   f   g   h   i   j
+    "\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33";
+//     k   l   m   n   o   p   q   r   s   t   u   v   w   x   y   z
+
+/**
+ * Base64-decode a string
+ *
+ * @v encoded	Encoded string
+ * @v raw		Buffer for raw data
+ * @ret rc		Return length of the decoded data or -1 to indicate an error
+ *
+ * The buffer must be the correct length for the raw data.  Use
+ * something like
+ *
+ *     char buf[ base64_decode_buf_len ( strlen ( encoded ) ) ];
+ *
+ * to provide a buffer of the correct size.
+ */
+int base64_decode ( const char *encoded, char *raw ) {
+	size_t encoded_len =  strlen ( encoded );
+	size_t len = ( encoded_len / 4 ) * 3;
+	unsigned int byte;
+	unsigned int i;
+	unsigned char buf[4];
+
+	if ( encoded_len % 4 != 0 )
+		return -1;
+
+	for ( byte = 0 ; byte < len ; byte += 3 ) {
+		for  ( i = 0 ; i < 4 ; ++i) {
+			if ( ( *encoded < '+' ) || ( *encoded > 'z' ) )
+				return -1;
+
+			buf[ i ] = base64d[ *(encoded++) - '+' ];
+
+			if ( buf[ i ] & 0x80 ) {
+				if ( ( buf[ i ] == 0xc0 ) && ( byte + i + 1 >= len ) &&
+						( ( i == 3 ) || ( *encoded == '=' ) ) ) {
+					buf[ i ] = 0;
+					--len;
+				} else {
+					return -1;
+				}
+			}
+		}
+
+		/*
+		 * this loop does:
+		 * *(raw++) = ( buf[ 0 ] << 2 ) | ( buf[ 1 ] >> 4 );
+		 * *(raw++) = ( buf[ 1 ] << 4 ) | ( buf[ 2 ] >> 2 );
+		 * *(raw++) = ( buf[ 2 ] << 6 ) | ( buf[ 3 ] >> 0 );
+		 */
+		for ( i = 0 ; i < 3 ; ++i )
+			*(raw++) = ( buf[ i ] << ( i * 2 + 2 ) ) |
+				( buf[ i + 1 ] >> ( 4 - i * 2 ) );
+	}
+
+	DBG ( "Base64-decoded \"%s\" to \"%s\"\n", encoded, raw );
+
+	return len;
+}
diff --git a/src/include/gpxe/base64.h b/src/include/gpxe/base64.h
index e38bef0..e4255a3 100644
--- a/src/include/gpxe/base64.h
+++ b/src/include/gpxe/base64.h
@@ -21,6 +21,18 @@ static inline size_t base64_encoded_len ( size_t raw_len ) {
 	return ( ( ( raw_len + 3 - 1 ) / 3 ) * 4 );
 }
 
+/**
+ * Calculate length of the buffer needed to base64-decode string
+ *
+ * @v encoded_len	Encoded string length (excluding NUL)
+ * @ret buf_len		Buffer length
+ */
+static inline size_t base64_decode_buf_len ( size_t encoded_len ) {
+	return ( ( encoded_len / 4 ) * 3 );
+}
+
 extern void base64_encode ( const char *raw, char *encoded );
 
+extern int base64_decode ( const char *encoded, char *raw );
+
 #endif /* _GPXE_BASE64_H */
-- 
1.7.1

From 879bf68ae5815c56fe48a2bc1935f6f10f282d14 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Piotr=20Jaroszy=C5=84ski?= <[email protected]>
Date: Sat, 27 Mar 2010 02:15:36 +0100
Subject: [PATCH 2/2] [iscsi] Add base64 support for CHAP.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Piotr JaroszyĹ„ski <[email protected]>
---
 src/net/tcp/iscsi.c |   89 +++++++++++++++++++++++++++------------------------
 1 files changed, 47 insertions(+), 42 deletions(-)

diff --git a/src/net/tcp/iscsi.c b/src/net/tcp/iscsi.c
index b13a107..c6708ae 100644
--- a/src/net/tcp/iscsi.c
+++ b/src/net/tcp/iscsi.c
@@ -35,6 +35,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <gpxe/tcpip.h>
 #include <gpxe/settings.h>
 #include <gpxe/features.h>
+#include <gpxe/base64.h>
 #include <gpxe/iscsi.h>
 
 /** @file
@@ -731,6 +732,38 @@ static int iscsi_handle_chap_i_value ( struct iscsi_session *iscsi,
 	return 0;
 }
 
+static int iscsi_decode_hex ( const char * encoded, char * raw )
+{
+	char *endp;
+	char buf[3];
+	unsigned int i;
+
+	buf[2] = 0;
+
+	for ( i = 0 ; ( encoded[0] && encoded[1] ) ; encoded += 2, i++ ) {
+		memcpy ( buf, encoded, 2 );
+		raw[i] = strtoul ( buf, &endp, 16 );
+		if ( *endp != '\0' ) {
+			return -1;
+		}
+	}
+
+	return i;
+}
+
+static int iscsi_decode_large_binary ( const char * encoded, char * raw )
+{
+	if ( encoded[0] != '0' )
+		return -1;
+
+	if ( ( encoded[1] == 'x' ) || ( encoded[1] == 'X' ) )
+		return iscsi_decode_hex ( encoded + 2, raw );
+	if ( ( encoded[1] == 'b' ) || ( encoded[1] == 'B' ) )
+		return base64_decode ( encoded + 2, raw );
+
+	return -1;
+}
+
 /**
  * Handle iSCSI CHAP_C text value
  *
@@ -740,31 +773,17 @@ static int iscsi_handle_chap_i_value ( struct iscsi_session *iscsi,
  */
 static int iscsi_handle_chap_c_value ( struct iscsi_session *iscsi,
 				       const char *value ) {
-	char buf[3];
-	char *endp;
-	uint8_t byte;
 	unsigned int i;
+	char raw[ base64_decode_buf_len ( strlen ( value ) ) ];
+	int len;
 
-	/* Check and strip leading "0x" */
-	if ( ( value[0] != '0' ) || ( value[1] != 'x' ) ) {
+	if ( ( len = iscsi_decode_large_binary ( value, raw ) ) < 0 ) {
 		DBGC ( iscsi, "iSCSI %p saw invalid CHAP challenge \"%s\"\n",
 		       iscsi, value );
 		return -EPROTO_INVALID_CHAP_CHALLENGE;
 	}
-	value += 2;
 
-	/* Process challenge an octet at a time */
-	for ( ; ( value[0] && value[1] ) ; value += 2 ) {
-		memcpy ( buf, value, 2 );
-		buf[2] = 0;
-		byte = strtoul ( buf, &endp, 16 );
-		if ( *endp != '\0' ) {
-			DBGC ( iscsi, "iSCSI %p saw invalid CHAP challenge "
-			       "byte \"%s\"\n", iscsi, buf );
-			return -EPROTO_INVALID_CHAP_CHALLENGE;
-		}
-		chap_update ( &iscsi->chap, &byte, sizeof ( byte ) );
-	}
+	chap_update ( &iscsi->chap, raw, len );
 
 	/* Build CHAP response */
 	DBGC ( iscsi, "iSCSI %p sending CHAP response\n", iscsi );
@@ -821,11 +840,9 @@ static int iscsi_handle_chap_n_value ( struct iscsi_session *iscsi,
  */
 static int iscsi_handle_chap_r_value ( struct iscsi_session *iscsi,
 				       const char *value ) {
-	char buf[3];
-	char *endp;
-	uint8_t byte;
-	unsigned int i;
 	int rc;
+	char raw[ base64_decode_buf_len ( strlen ( value ) ) ];
+	size_t len;
 
 	/* Generate CHAP response for verification */
 	chap_finish ( &iscsi->chap );
@@ -843,38 +860,26 @@ static int iscsi_handle_chap_r_value ( struct iscsi_session *iscsi,
 		      ( sizeof ( iscsi->chap_challenge ) - 1 ) );
 	chap_respond ( &iscsi->chap );
 
-	/* Check and strip leading "0x" */
-	if ( ( value[0] != '0' ) || ( value[1] != 'x' ) ) {
+	if ( ( rc = iscsi_decode_large_binary ( value, raw ) ) < 0 ) {
 		DBGC ( iscsi, "iSCSI %p saw invalid CHAP response \"%s\"\n",
 		       iscsi, value );
 		return -EPROTO_INVALID_CHAP_RESPONSE;
 	}
-	value += 2;
+
+	len = rc;
 
 	/* Check CHAP response length */
-	if ( strlen ( value ) != ( 2 * iscsi->chap.response_len ) ) {
+	if ( len != iscsi->chap.response_len ) {
 		DBGC ( iscsi, "iSCSI %p invalid CHAP response length\n",
 		       iscsi );
 		return -EPROTO_INVALID_CHAP_RESPONSE;
 	}
 
-	/* Process response an octet at a time */
-	for ( i = 0 ; ( value[0] && value[1] ) ; value += 2, i++ ) {
-		memcpy ( buf, value, 2 );
-		buf[2] = 0;
-		byte = strtoul ( buf, &endp, 16 );
-		if ( *endp != '\0' ) {
-			DBGC ( iscsi, "iSCSI %p saw invalid CHAP response "
-			       "byte \"%s\"\n", iscsi, buf );
-			return -EPROTO_INVALID_CHAP_RESPONSE;
-		}
-		if ( byte != iscsi->chap.response[i] ) {
-			DBGC ( iscsi, "iSCSI %p saw incorrect CHAP "
-			       "response\n", iscsi );
-			return -EACCES_INCORRECT_TARGET_PASSWORD;
-		}
+	if ( memcmp ( raw, iscsi->chap.response, len ) != 0 ) {
+		DBGC ( iscsi, "iSCSI %p saw incorrect CHAP "
+			"response\n", iscsi );
+		return -EACCES_INCORRECT_TARGET_PASSWORD;
 	}
-	assert ( i == iscsi->chap.response_len );
 
 	/* Mark session as authenticated */
 	iscsi->status |= ISCSI_STATUS_AUTH_REVERSE_OK;
-- 
1.7.1

_______________________________________________
gPXE-devel mailing list
[email protected]
http://etherboot.org/mailman/listinfo/gpxe-devel

Reply via email to