|
@@ -509,17 +509,13 @@ static void iscsi_tx_login_request ( struct iscsi_session *iscsi,
|
509
|
509
|
* Handle iSCSI AuthMethod text value
|
510
|
510
|
*
|
511
|
511
|
* @v iscsi iSCSI session
|
512
|
|
- * @v finished Value is complete
|
|
512
|
+ * @v value AuthMethod value
|
513
|
513
|
*/
|
514
|
514
|
static void iscsi_handle_authmethod_value ( struct iscsi_session *iscsi,
|
515
|
|
- int finished ) {
|
516
|
|
- struct iscsi_string_state *string = &iscsi->string;
|
517
|
|
-
|
518
|
|
- if ( ! finished )
|
519
|
|
- return;
|
|
515
|
+ const char *value ) {
|
520
|
516
|
|
521
|
517
|
/* If server requests CHAP, send the CHAP_A string */
|
522
|
|
- if ( strcmp ( string->value, "CHAP" ) == 0 ) {
|
|
518
|
+ if ( strcmp ( value, "CHAP" ) == 0 ) {
|
523
|
519
|
DBG ( "iSCSI %p initiating CHAP authentication\n", iscsi );
|
524
|
520
|
iscsi->status |= ISCSI_STATUS_STRINGS_CHAP_ALGORITHM;
|
525
|
521
|
}
|
|
@@ -529,23 +525,19 @@ static void iscsi_handle_authmethod_value ( struct iscsi_session *iscsi,
|
529
|
525
|
* Handle iSCSI CHAP_A text value
|
530
|
526
|
*
|
531
|
527
|
* @v iscsi iSCSI session
|
532
|
|
- * @v finished Value is complete
|
|
528
|
+ * @v value CHAP_A value
|
533
|
529
|
*/
|
534
|
530
|
static void iscsi_handle_chap_a_value ( struct iscsi_session *iscsi,
|
535
|
|
- int finished ) {
|
536
|
|
- struct iscsi_string_state *string = &iscsi->string;
|
|
531
|
+ const char *value ) {
|
537
|
532
|
int rc;
|
538
|
533
|
|
539
|
|
- if ( ! finished )
|
540
|
|
- return;
|
541
|
|
-
|
542
|
534
|
/* We only ever offer "5" (i.e. MD5) as an algorithm, so if
|
543
|
535
|
* the server responds with anything else it is a protocol
|
544
|
536
|
* violation.
|
545
|
537
|
*/
|
546
|
|
- if ( strcmp ( string->value, "5" ) != 0 ) {
|
|
538
|
+ if ( strcmp ( value, "5" ) != 0 ) {
|
547
|
539
|
DBG ( "iSCSI %p got invalid CHAP algorithm \"%s\"\n",
|
548
|
|
- iscsi, string->value );
|
|
540
|
+ iscsi, value );
|
549
|
541
|
}
|
550
|
542
|
|
551
|
543
|
/* Prepare for CHAP with MD5 */
|
|
@@ -559,22 +551,18 @@ static void iscsi_handle_chap_a_value ( struct iscsi_session *iscsi,
|
559
|
551
|
* Handle iSCSI CHAP_I text value
|
560
|
552
|
*
|
561
|
553
|
* @v iscsi iSCSI session
|
562
|
|
- * @v finished Value is complete
|
|
554
|
+ * @v value CHAP_I value
|
563
|
555
|
*/
|
564
|
556
|
static void iscsi_handle_chap_i_value ( struct iscsi_session *iscsi,
|
565
|
|
- int finished ) {
|
566
|
|
- struct iscsi_string_state *string = &iscsi->string;
|
|
557
|
+ const char *value ) {
|
567
|
558
|
unsigned int identifier;
|
568
|
559
|
char *endp;
|
569
|
560
|
|
570
|
|
- if ( ! finished )
|
571
|
|
- return;
|
572
|
|
-
|
573
|
561
|
/* The CHAP identifier is an integer value */
|
574
|
|
- identifier = strtoul ( string->value, &endp, 0 );
|
|
562
|
+ identifier = strtoul ( value, &endp, 0 );
|
575
|
563
|
if ( *endp != '\0' ) {
|
576
|
564
|
DBG ( "iSCSI %p saw invalid CHAP identifier \"%s\"\n",
|
577
|
|
- iscsi, string->value );
|
|
565
|
+ iscsi, value );
|
578
|
566
|
}
|
579
|
567
|
|
580
|
568
|
/* Identifier and secret are the first two components of the
|
|
@@ -589,159 +577,108 @@ static void iscsi_handle_chap_i_value ( struct iscsi_session *iscsi,
|
589
|
577
|
* Handle iSCSI CHAP_C text value
|
590
|
578
|
*
|
591
|
579
|
* @v iscsi iSCSI session
|
592
|
|
- * @v finished Value is complete
|
|
580
|
+ * @v value CHAP_C value
|
593
|
581
|
*/
|
594
|
582
|
static void iscsi_handle_chap_c_value ( struct iscsi_session *iscsi,
|
595
|
|
- int finished ) {
|
596
|
|
- struct iscsi_string_state *string = &iscsi->string;
|
597
|
|
- uint8_t byte;
|
|
583
|
+ const char *value ) {
|
|
584
|
+ char buf[3];
|
598
|
585
|
char *endp;
|
|
586
|
+ uint8_t byte;
|
599
|
587
|
|
600
|
|
- /* Once the whole challenge is received, calculate the response */
|
601
|
|
- if ( finished ) {
|
602
|
|
- DBG ( "iSCSI %p sending CHAP response\n", iscsi );
|
603
|
|
- chap_respond ( &iscsi->chap );
|
604
|
|
- iscsi->status |= ISCSI_STATUS_STRINGS_CHAP_RESPONSE;
|
605
|
|
- return;
|
|
588
|
+ /* Check and strip leading "0x" */
|
|
589
|
+ if ( ( value[0] != '0' ) || ( value[1] != 'x' ) ) {
|
|
590
|
+ DBG ( "iSCSI %p saw invalid CHAP challenge \"%s\"\n",
|
|
591
|
+ iscsi, value );
|
606
|
592
|
}
|
607
|
|
-
|
608
|
|
- /* Wait until a complete octet ("0x??") is received */
|
609
|
|
- if ( string->index != 4 )
|
610
|
|
- return;
|
611
|
|
-
|
612
|
|
- /* Add octet to challenge */
|
613
|
|
- byte = strtoul ( string->value, &endp, 0 );
|
614
|
|
- if ( *endp != '\0' ) {
|
615
|
|
- DBG ( "iSCSI %p saw invalid CHAP challenge portion \"%s\"\n",
|
616
|
|
- iscsi, string->value );
|
|
593
|
+ value += 2;
|
|
594
|
+
|
|
595
|
+ /* Process challenge an octet at a time */
|
|
596
|
+ for ( ; ( value[0] && value[1] ) ; value += 2 ) {
|
|
597
|
+ memcpy ( buf, value, 2 );
|
|
598
|
+ buf[3] = 0;
|
|
599
|
+ byte = strtoul ( buf, &endp, 16 );
|
|
600
|
+ if ( *endp != '\0' ) {
|
|
601
|
+ DBG ( "iSCSI %p saw invalid CHAP challenge byte "
|
|
602
|
+ "\"%s\"\n", iscsi, buf );
|
|
603
|
+ }
|
|
604
|
+ chap_update ( &iscsi->chap, &byte, sizeof ( byte ) );
|
617
|
605
|
}
|
618
|
|
- chap_update ( &iscsi->chap, &byte, sizeof ( byte ) );
|
619
|
606
|
|
620
|
|
- /* Reset value back to "0x" */
|
621
|
|
- string->index = 2;
|
|
607
|
+ /* Build CHAP response */
|
|
608
|
+ DBG ( "iSCSI %p sending CHAP response\n", iscsi );
|
|
609
|
+ chap_respond ( &iscsi->chap );
|
|
610
|
+ iscsi->status |= ISCSI_STATUS_STRINGS_CHAP_RESPONSE;
|
622
|
611
|
}
|
623
|
612
|
|
624
|
613
|
/** An iSCSI text string that we want to handle */
|
625
|
614
|
struct iscsi_string_type {
|
626
|
|
- /** String name
|
|
615
|
+ /** String key
|
627
|
616
|
*
|
628
|
|
- * This is the portion before the "=" sign,
|
629
|
|
- * e.g. InitiatorName, CHAP_A, etc.
|
|
617
|
+ * This is the portion up to and including the "=" sign,
|
|
618
|
+ * e.g. "InitiatorName=", "CHAP_A=", etc.
|
630
|
619
|
*/
|
631
|
|
- const char *name;
|
|
620
|
+ const char *key;
|
632
|
621
|
/** Handle iSCSI string value
|
633
|
622
|
*
|
634
|
623
|
* @v iscsi iSCSI session
|
635
|
|
- * @v finished Value is complete
|
636
|
|
- *
|
637
|
|
- * Process the string in @c iscsi->string. This method will
|
638
|
|
- * be called once for each character in the string, and once
|
639
|
|
- * again at the end of the string.
|
|
624
|
+ * @v value iSCSI string value
|
640
|
625
|
*/
|
641
|
|
- void ( * handle_value ) ( struct iscsi_session *iscsi, int finished );
|
|
626
|
+ void ( * handle_value ) ( struct iscsi_session *iscsi,
|
|
627
|
+ const char *value );
|
642
|
628
|
};
|
643
|
629
|
|
644
|
630
|
/** iSCSI text strings that we want to handle */
|
645
|
631
|
struct iscsi_string_type iscsi_string_types[] = {
|
646
|
|
- { "AuthMethod", iscsi_handle_authmethod_value },
|
647
|
|
- { "CHAP_A", iscsi_handle_chap_a_value },
|
648
|
|
- { "CHAP_I", iscsi_handle_chap_i_value },
|
649
|
|
- { "CHAP_C", iscsi_handle_chap_c_value },
|
|
632
|
+ { "AuthMethod=", iscsi_handle_authmethod_value },
|
|
633
|
+ { "CHAP_A=", iscsi_handle_chap_a_value },
|
|
634
|
+ { "CHAP_I=", iscsi_handle_chap_i_value },
|
|
635
|
+ { "CHAP_C=", iscsi_handle_chap_c_value },
|
650
|
636
|
{ NULL, NULL }
|
651
|
637
|
};
|
652
|
638
|
|
653
|
639
|
/**
|
654
|
|
- * Handle iSCSI string value
|
|
640
|
+ * Handle iSCSI string
|
655
|
641
|
*
|
656
|
642
|
* @v iscsi iSCSI session
|
657
|
|
- * @v finished Value is complete
|
658
|
|
- *
|
659
|
|
- * Process the string in @c iscsi->string. This function will be
|
660
|
|
- * called once for each character in the string, and once again at the
|
661
|
|
- * end of the string.
|
|
643
|
+ * @v string iSCSI string (in "key=value" format)
|
662
|
644
|
*/
|
663
|
|
-static void iscsi_handle_string_value ( struct iscsi_session *iscsi,
|
664
|
|
- int finished ) {
|
665
|
|
- struct iscsi_string_state *string = &iscsi->string;
|
666
|
|
- struct iscsi_string_type *type = iscsi_string_types;
|
667
|
|
-
|
668
|
|
- assert ( string->key_value == STRING_VALUE );
|
669
|
|
-
|
670
|
|
- for ( type = iscsi_string_types ; type->name ; type++ ) {
|
671
|
|
- if ( strcmp ( type->name, string->key ) == 0 ) {
|
672
|
|
- if ( string->index <= 1 ) {
|
673
|
|
- DBG ( "iSCSI %p handling key \"%s\"\n",
|
674
|
|
- iscsi, string->key );
|
675
|
|
- }
|
676
|
|
- type->handle_value ( iscsi, finished );
|
|
645
|
+static void iscsi_handle_string ( struct iscsi_session *iscsi,
|
|
646
|
+ const char *string ) {
|
|
647
|
+ struct iscsi_string_type *type;
|
|
648
|
+ size_t key_len;
|
|
649
|
+
|
|
650
|
+ for ( type = iscsi_string_types ; type->key ; type++ ) {
|
|
651
|
+ key_len = strlen ( type->key );
|
|
652
|
+ if ( strncmp ( string, type->key, key_len ) == 0 ) {
|
|
653
|
+ DBG ( "iSCSI %p handling %s\n", iscsi, string );
|
|
654
|
+ type->handle_value ( iscsi, ( string + key_len ) );
|
677
|
655
|
return;
|
678
|
656
|
}
|
679
|
657
|
}
|
680
|
|
- if ( string->index <= 1 )
|
681
|
|
- DBG ( "iSCSI %p ignoring key \"%s\"\n", iscsi, string->key );
|
|
658
|
+ DBG ( "iSCSI %p ignoring %s\n", iscsi, string );
|
682
|
659
|
}
|
683
|
660
|
|
684
|
661
|
/**
|
685
|
|
- * Handle byte of an iSCSI string
|
|
662
|
+ * Handle iSCSI strings
|
686
|
663
|
*
|
687
|
664
|
* @v iscsi iSCSI session
|
688
|
|
- * @v byte Byte of string
|
689
|
|
- *
|
690
|
|
- * Strings are handled a byte at a time in order to simplify the
|
691
|
|
- * logic, and to ensure that we can provably cope with the TCP packet
|
692
|
|
- * boundaries coming at inconvenient points, such as halfway through a
|
693
|
|
- * string.
|
|
665
|
+ * @v string iSCSI string buffer
|
|
666
|
+ * @v len Length of string buffer
|
694
|
667
|
*/
|
695
|
|
-static void iscsi_handle_string_byte ( struct iscsi_session *iscsi,
|
696
|
|
- uint8_t byte ) {
|
697
|
|
- struct iscsi_string_state *string = &iscsi->string;
|
698
|
|
-
|
699
|
|
- if ( string->key_value == STRING_KEY ) {
|
700
|
|
- switch ( byte ) {
|
701
|
|
- case '\0':
|
702
|
|
- /* Premature termination */
|
703
|
|
- DBG ( "iSCSI %p premature key termination on \"%s\"\n",
|
704
|
|
- iscsi, string->key );
|
705
|
|
- string->index = 0;
|
706
|
|
- break;
|
707
|
|
- case '=':
|
708
|
|
- /* End of key */
|
709
|
|
- string->key_value = STRING_VALUE;
|
710
|
|
- string->index = 0;
|
711
|
|
- break;
|
712
|
|
- default:
|
713
|
|
- /* Part of key */
|
714
|
|
- if ( string->index < ( sizeof ( string->key ) - 1 ) ) {
|
715
|
|
- string->key[string->index++] = byte;
|
716
|
|
- string->key[string->index] = '\0';
|
717
|
|
- }
|
718
|
|
- break;
|
719
|
|
- }
|
720
|
|
- } else {
|
721
|
|
- switch ( byte ) {
|
722
|
|
- case '\0':
|
723
|
|
- /* End of string */
|
724
|
|
- iscsi_handle_string_value ( iscsi, 1 );
|
725
|
|
- string->key_value = STRING_KEY;
|
726
|
|
- string->index = 0;
|
727
|
|
- break;
|
728
|
|
- default:
|
729
|
|
- /* Part of value */
|
730
|
|
- if ( string->index < ( sizeof ( string->value ) - 1 )){
|
731
|
|
- string->value[string->index++] = byte;
|
732
|
|
- string->value[string->index] = '\0';
|
733
|
|
- iscsi_handle_string_value ( iscsi, 0 );
|
734
|
|
- }
|
735
|
|
- break;
|
736
|
|
- }
|
737
|
|
- }
|
738
|
|
-}
|
739
|
|
-
|
740
|
668
|
static void iscsi_handle_strings ( struct iscsi_session *iscsi,
|
741
|
669
|
const char *strings, size_t len ) {
|
742
|
|
- for ( ; len-- ; strings++ ) {
|
743
|
|
- iscsi_handle_string_byte ( iscsi,
|
744
|
|
- * ( ( uint8_t * ) strings ) );
|
|
670
|
+ size_t string_len;
|
|
671
|
+
|
|
672
|
+ /* Handle each string in turn, taking care not to overrun the
|
|
673
|
+ * data buffer in case of badly-terminated data.
|
|
674
|
+ */
|
|
675
|
+ while ( 1 ) {
|
|
676
|
+ string_len = ( strnlen ( strings, len ) + 1 );
|
|
677
|
+ if ( string_len > len )
|
|
678
|
+ break;
|
|
679
|
+ iscsi_handle_string ( iscsi, strings );
|
|
680
|
+ strings += string_len;
|
|
681
|
+ len -= string_len;
|
745
|
682
|
}
|
746
|
683
|
}
|
747
|
684
|
|