]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[iscsi] Include credentials in iBFT only if used during iSCSI login
authorMichael Brown <mcb30@etherboot.org>
Fri, 20 Feb 2009 21:41:00 +0000 (21:41 +0000)
committerMichael Brown <mcb30@etherboot.org>
Fri, 20 Feb 2009 21:41:00 +0000 (21:41 +0000)
Avoid passing credentials in the iBFT that were available but not
required for login.  This works around a problem in the Microsoft
iSCSI initiator, which will refuse to initiate sessions if the CHAP
password is fewer than 12 characters, even if the target ends up not
asking for CHAP authentication.

src/arch/i386/interface/pcbios/ibft.c
src/include/gpxe/iscsi.h
src/net/tcp/iscsi.c

index ffa65964a655367d05d1dbee39a8c9fb2ad3c89b..43d1f85f9f022feee85a84dd3fd5fbb85891044f 100644 (file)
@@ -136,6 +136,17 @@ static void ibft_set_ipaddr_option ( struct ibft_ipaddr *ipaddr,
        ibft_set_ipaddr ( ipaddr, in );
 }
 
+/**
+ * Read IP address from iBFT (for debugging)
+ *
+ * @v strings          iBFT string block descriptor
+ * @v string           String field
+ * @ret ipaddr         IP address string
+ */
+static const char * ibft_ipaddr ( struct ibft_ipaddr *ipaddr ) {
+       return inet_ntoa ( ipaddr->in );
+}
+
 /**
  * Allocate a string within iBFT
  *
@@ -214,6 +225,18 @@ static int ibft_set_string_option ( struct ibft_string_block *strings,
        return 0;
 }
 
+/**
+ * Read string from iBFT (for debugging)
+ *
+ * @v strings          iBFT string block descriptor
+ * @v string           String field
+ * @ret data           String content (or "<empty>")
+ */
+static const char * ibft_string ( struct ibft_string_block *strings,
+                                 struct ibft_string *string ) {
+       return ( ( ( char * ) strings->table ) + string->offset );
+}
+
 /**
  * Fill in NIC portion of iBFT
  *
@@ -231,11 +254,16 @@ static int ibft_fill_nic ( struct ibft_nic *nic,
 
        /* Extract values from DHCP configuration */
        ibft_set_ipaddr_option ( &nic->ip_address, &ip_setting );
+       DBG ( "iBFT NIC IP = %s\n", ibft_ipaddr ( &nic->ip_address ) );
        ibft_set_ipaddr_option ( &nic->gateway, &gateway_setting );
+       DBG ( "iBFT NIC gateway = %s\n", ibft_ipaddr ( &nic->gateway ) );
        ibft_set_ipaddr_option ( &nic->dns[0], &dns_setting );
+       DBG ( "iBFT NIC DNS = %s\n", ibft_ipaddr ( &nic->dns[0] ) );
        if ( ( rc = ibft_set_string_option ( strings, &nic->hostname,
                                             &hostname_setting ) ) != 0 )
                return rc;
+       DBG ( "iBFT NIC hostname = %s\n",
+             ibft_string ( strings, &nic->hostname ) );
 
        /* Derive subnet mask prefix from subnet mask */
        fetch_ipv4_setting ( NULL, &netmask_setting, &netmask_addr );
@@ -245,11 +273,15 @@ static int ibft_fill_nic ( struct ibft_nic *nic,
                netmask_addr.s_addr >>= 1;
        }
        nic->subnet_mask_prefix = netmask_count;
+       DBG ( "iBFT NIC subnet = /%d\n", nic->subnet_mask_prefix );
 
        /* Extract values from net-device configuration */
        memcpy ( nic->mac_address, netdev->ll_addr,
                 sizeof ( nic->mac_address ) );
+       DBG ( "iBFT NIC MAC = %s\n",
+             netdev->ll_protocol->ntoa ( nic->mac_address ) );
        nic->pci_bus_dev_func = netdev->dev->desc.location;
+       DBG ( "iBFT NIC PCI = %04x\n", nic->pci_bus_dev_func );
 
        return 0;
 }
@@ -269,6 +301,8 @@ static int ibft_fill_initiator ( struct ibft_initiator *initiator,
        if ( ( rc = ibft_set_string ( strings, &initiator->initiator_name,
                                      initiator_iqn ) ) != 0 )
                return rc;
+       DBG ( "iBFT initiator hostname = %s\n",
+             ibft_string ( strings, &initiator->initiator_name ) );
 
        return 0;
 }
@@ -286,17 +320,23 @@ static int ibft_fill_target_chap ( struct ibft_target *target,
                                   struct iscsi_session *iscsi ) {
        int rc;
 
-       if ( ! iscsi->initiator_username )
+       if ( ! ( iscsi->status & ISCSI_STATUS_AUTH_FORWARD_REQUIRED ) )
                return 0;
+
+       assert ( iscsi->initiator_username );
        assert ( iscsi->initiator_password );
 
        target->chap_type = IBFT_CHAP_ONE_WAY;
        if ( ( rc = ibft_set_string ( strings, &target->chap_name,
                                      iscsi->initiator_username ) ) != 0 )
                return rc;
+       DBG ( "iBFT target username = %s\n",
+             ibft_string ( strings, &target->chap_name ) );
        if ( ( rc = ibft_set_string ( strings, &target->chap_secret,
                                      iscsi->initiator_password ) ) != 0 )
                return rc;
+       DBG ( "iBFT target password = <redacted>\n" );
+
        return 0;
 }
 
@@ -313,19 +353,25 @@ static int ibft_fill_target_reverse_chap ( struct ibft_target *target,
                                           struct iscsi_session *iscsi ) {
        int rc;
 
-       if ( ! iscsi->target_username )
+       if ( ! ( iscsi->status & ISCSI_STATUS_AUTH_REVERSE_REQUIRED ) )
                return 0;
-       assert ( iscsi->target_password );
+
        assert ( iscsi->initiator_username );
        assert ( iscsi->initiator_password );
+       assert ( iscsi->target_username );
+       assert ( iscsi->target_password );
 
        target->chap_type = IBFT_CHAP_MUTUAL;
        if ( ( rc = ibft_set_string ( strings, &target->reverse_chap_name,
                                      iscsi->target_username ) ) != 0 )
                return rc;
+       DBG ( "iBFT target reverse username = %s\n",
+             ibft_string ( strings, &target->chap_name ) );
        if ( ( rc = ibft_set_string ( strings, &target->reverse_chap_secret,
                                      iscsi->target_password ) ) != 0 )
                return rc;
+       DBG ( "iBFT target reverse password = <redacted>\n" );
+
        return 0;
 }
 
@@ -346,10 +392,14 @@ static int ibft_fill_target ( struct ibft_target *target,
 
        /* Fill in Target values */
        ibft_set_ipaddr ( &target->ip_address, sin_target->sin_addr );
+       DBG ( "iBFT target IP = %s\n", ibft_ipaddr ( &target->ip_address ) );
        target->socket = ntohs ( sin_target->sin_port );
+       DBG ( "iBFT target port = %d\n", target->socket );
        if ( ( rc = ibft_set_string ( strings, &target->target_name,
                                      iscsi->target_iqn ) ) != 0 )
                return rc;
+       DBG ( "iBFT target name = %s\n",
+             ibft_string ( strings, &target->target_name ) );
        if ( ( rc = ibft_fill_target_chap ( target, strings, iscsi ) ) != 0 )
                return rc;
        if ( ( rc = ibft_fill_target_reverse_chap ( target, strings,
index fd96fdfe09ed68c872f2b45549d57a4d965bb1ca..0510974e8786ee052e9dc546e623b158bbf20fef 100644 (file)
@@ -530,8 +530,6 @@ struct iscsi_session {
        char *target_username;
        /** Target password (if any) */
        char *target_password;
-       /** Target has authenticated acceptably */
-       int target_auth_ok;
        /** CHAP challenge (for target auth only)
         *
         * This is a block of random data; the first byte is used as
@@ -664,6 +662,15 @@ struct iscsi_session {
 /** Mask for all iSCSI "needs to send" flags */
 #define ISCSI_STATUS_STRINGS_MASK 0xff00
 
+/** Target has requested forward (initiator) authentication */
+#define ISCSI_STATUS_AUTH_FORWARD_REQUIRED 0x00010000
+
+/** Initiator requires target (reverse) authentication */
+#define ISCSI_STATUS_AUTH_REVERSE_REQUIRED 0x00020000
+
+/** Target authenticated itself correctly */
+#define ISCSI_STATUS_AUTH_REVERSE_OK 0x00040000
+
 /** Maximum number of retries at connecting */
 #define ISCSI_MAX_RETRIES 2
 
index aa99db71c2abcde5fe2e1afa6ad4e262e9a6a7ae..45519e667c4ca2ac3e8a7541a7d6b40769176bde 100644 (file)
@@ -125,6 +125,8 @@ static int iscsi_open_connection ( struct iscsi_session *iscsi ) {
        /* Enter security negotiation phase */
        iscsi->status = ( ISCSI_STATUS_SECURITY_NEGOTIATION_PHASE |
                          ISCSI_STATUS_STRINGS_SECURITY );
+       if ( iscsi->target_username )
+               iscsi->status |= ISCSI_STATUS_AUTH_REVERSE_REQUIRED;
 
        /* Assign fresh initiator task tag */
        iscsi->itt++;
@@ -152,9 +154,6 @@ static void iscsi_close_connection ( struct iscsi_session *iscsi, int rc ) {
        /* Clear connection status */
        iscsi->status = 0;
 
-       /* Deauthenticate target */
-       iscsi->target_auth_ok = 0;
-
        /* Reset TX and RX state machines */
        iscsi->tx_state = ISCSI_TX_IDLE;
        iscsi->rx_state = ISCSI_RX_BHS;
@@ -634,15 +633,12 @@ static int iscsi_handle_targetaddress_value ( struct iscsi_session *iscsi,
 static int iscsi_handle_authmethod_value ( struct iscsi_session *iscsi,
                                           const char *value ) {
 
-       /* Mark target as authenticated if no authentication required */
-       if ( ! iscsi->target_username )
-               iscsi->target_auth_ok = 1;
-
        /* If server requests CHAP, send the CHAP_A string */
        if ( strcmp ( value, "CHAP" ) == 0 ) {
                DBGC ( iscsi, "iSCSI %p initiating CHAP authentication\n",
                       iscsi );
-               iscsi->status |= ISCSI_STATUS_STRINGS_CHAP_ALGORITHM;
+               iscsi->status |= ( ISCSI_STATUS_STRINGS_CHAP_ALGORITHM |
+                                  ISCSI_STATUS_AUTH_FORWARD_REQUIRED );
        }
 
        return 0;
@@ -858,7 +854,7 @@ static int iscsi_handle_chap_r_value ( struct iscsi_session *iscsi,
        assert ( i == iscsi->chap.response_len );
 
        /* Mark session as authenticated */
-       iscsi->target_auth_ok = 1;
+       iscsi->status |= ISCSI_STATUS_AUTH_REVERSE_OK;
 
        return 0;
 }
@@ -1064,14 +1060,16 @@ static int iscsi_rx_login_response ( struct iscsi_session *iscsi,
 
        /* Handle login transitions */
        if ( response->flags & ISCSI_LOGIN_FLAG_TRANSITION ) {
+               iscsi->status &= ~( ISCSI_STATUS_PHASE_MASK |
+                                   ISCSI_STATUS_STRINGS_MASK );
                switch ( response->flags & ISCSI_LOGIN_NSG_MASK ) {
                case ISCSI_LOGIN_NSG_OPERATIONAL_NEGOTIATION:
-                       iscsi->status =
+                       iscsi->status |=
                                ( ISCSI_STATUS_OPERATIONAL_NEGOTIATION_PHASE |
                                  ISCSI_STATUS_STRINGS_OPERATIONAL );
                        break;
                case ISCSI_LOGIN_NSG_FULL_FEATURE_PHASE:
-                       iscsi->status = ISCSI_STATUS_FULL_FEATURE_PHASE;
+                       iscsi->status |= ISCSI_STATUS_FULL_FEATURE_PHASE;
                        break;
                default:
                        DBGC ( iscsi, "iSCSI %p got invalid response flags "
@@ -1090,7 +1088,8 @@ static int iscsi_rx_login_response ( struct iscsi_session *iscsi,
        }
 
        /* Check that target authentication was successful (if required) */
-       if ( ! iscsi->target_auth_ok ) {
+       if ( ( iscsi->status & ISCSI_STATUS_AUTH_REVERSE_REQUIRED ) &&
+            ! ( iscsi->status & ISCSI_STATUS_AUTH_REVERSE_OK ) ) {
                DBGC ( iscsi, "iSCSI %p nefarious target tried to bypass "
                       "authentication\n", iscsi );
                return -EPROTO;