? sys/dev/iscsi/iscsi_globals.h.debug-hack ? sys/dev/iscsi/iscsi_root.c Index: sys/dev/iscsi/iscsi_ioctl.c =================================================================== RCS file: /cvsroot/src/sys/dev/iscsi/iscsi_ioctl.c,v retrieving revision 1.34 diff -p -u -r1.34 iscsi_ioctl.c --- sys/dev/iscsi/iscsi_ioctl.c 25 Nov 2023 10:08:27 -0000 1.34 +++ sys/dev/iscsi/iscsi_ioctl.c 28 Dec 2023 21:00:58 -0000 @@ -1934,6 +1934,59 @@ iscsiioctl(struct file *fp, u_long cmd, get_version((iscsi_get_version_parameters_t *) addr); break; + case ISCSI_OLOGIN: + { + iscsi_old_login_parameters_t *opar; + iscsi_login_parameters_t par; + + opar = (iscsi_old_login_parameters_t *) addr; + +#define C(n,o,f) (n).f = (o)->f + C(par, opar, status); + C(par, opar, socket); + C(par, opar, is_present.HeaderDigest); + C(par, opar, is_present.DataDigest); + C(par, opar, is_present.MaxConnections); + C(par, opar, is_present.DefaultTime2Wait); + C(par, opar, is_present.DefaultTime2Retain); + C(par, opar, is_present.MaxRecvDataSegmentLength); + C(par, opar, is_present.auth_info); + C(par, opar, is_present.user_name); + C(par, opar, is_present.password); + C(par, opar, is_present.target_password); + C(par, opar, is_present.TargetName); + C(par, opar, is_present.TargetAlias); + C(par, opar, is_present.ErrorRecoveryLevel); + par.is_present.target_user_name = 0; + par.is_present.chap_algorithms = 0; + C(par, opar, auth_info); + C(par, opar, login_type); + C(par, opar, HeaderDigest); + C(par, opar, DataDigest); + C(par, opar, session_id); + C(par, opar, connection_id); + C(par, opar, MaxRecvDataSegmentLength); + C(par, opar, MaxConnections); + C(par, opar, DefaultTime2Wait); + C(par, opar, DefaultTime2Retain); + C(par, opar, ErrorRecoveryLevel); + C(par, opar, user_name); + C(par, opar, password); + C(par, opar, target_password); + C(par, opar, TargetName); + C(par, opar, TargetAlias); + par.target_user_name = NULL; + memset(&par.chap_algorithms, 0, sizeof(par.chap_algorithms)); +#undef C + + login(&par, l, d->fd_dev); + + opar->session_id = par.session_id; + opar->connection_id = par.connection_id; + opar->status = par.status; + } + break; + case ISCSI_LOGIN: login((iscsi_login_parameters_t *) addr, l, d->fd_dev); break; Index: sys/dev/iscsi/iscsi_ioctl.h =================================================================== RCS file: /cvsroot/src/sys/dev/iscsi/iscsi_ioctl.h,v retrieving revision 1.3 diff -p -u -r1.3 iscsi_ioctl.h --- sys/dev/iscsi/iscsi_ioctl.h 4 Apr 2013 22:17:13 -0000 1.3 +++ sys/dev/iscsi/iscsi_ioctl.h 28 Dec 2023 21:00:58 -0000 @@ -55,6 +55,8 @@ typedef struct { unsigned int TargetName:1; unsigned int TargetAlias:1; unsigned int ErrorRecoveryLevel:1; + unsigned int target_user_name:1; + unsigned int chap_algorithms:1; } is_present; iscsi_auth_info_t auth_info; iscsi_login_session_type_t login_type; @@ -72,8 +74,46 @@ typedef struct { void *target_password; void *TargetName; void *TargetAlias; + void *target_user_name; + uint64_t chap_algorithms[4]; /* bits 0..255 */ } iscsi_login_parameters_t; +typedef struct { + uint32_t status; + int socket; + struct { + unsigned int HeaderDigest:1; + unsigned int DataDigest:1; + unsigned int MaxConnections:1; + unsigned int DefaultTime2Wait:1; + unsigned int DefaultTime2Retain:1; + unsigned int MaxRecvDataSegmentLength:1; + unsigned int auth_info:1; + unsigned int user_name:1; + unsigned int password:1; + unsigned int target_password:1; + unsigned int TargetName:1; + unsigned int TargetAlias:1; + unsigned int ErrorRecoveryLevel:1; + } is_present; + iscsi_auth_info_t auth_info; + iscsi_login_session_type_t login_type; + iscsi_digest_t HeaderDigest; + iscsi_digest_t DataDigest; + uint32_t session_id; + uint32_t connection_id; + uint32_t MaxRecvDataSegmentLength; + uint16_t MaxConnections; + uint16_t DefaultTime2Wait; + uint16_t DefaultTime2Retain; + uint16_t ErrorRecoveryLevel; + void *user_name; + void *password; + void *target_password; + void *TargetName; + void *TargetAlias; +} iscsi_old_login_parameters_t; + /* status Contains, on return, the result of the command. @@ -148,6 +188,10 @@ typedef struct { TargetAlias Receives the target alias as a zero terminated UTF-8 string. When present, the buffer must be of size ISCSI_STRING_LENGTH. + target_user_name + Contains the user name to use during login authentication of the target + (zero terminated UTF-8 string). Required if mutual authentication is + requested. For compatibility we allow an empty name. */ @@ -423,7 +467,7 @@ typedef struct { /* ========================= IOCTL Codes =========================== */ #define ISCSI_GET_VERSION _IOWR(0, 1, iscsi_get_version_parameters_t) -#define ISCSI_LOGIN _IOWR(0, 2, iscsi_login_parameters_t) +#define ISCSI_OLOGIN _IOWR(0, 2, iscsi_old_login_parameters_t) #define ISCSI_LOGOUT _IOWR(0, 3, iscsi_logout_parameters_t) #define ISCSI_ADD_CONNECTION _IOWR(0, 4, iscsi_login_parameters_t) #define ISCSI_RESTORE_CONNECTION _IOWR(0, 5, iscsi_login_parameters_t) @@ -436,5 +480,6 @@ typedef struct { #define ISCSI_DEREGISTER_EVENT _IOWR(0, 12, iscsi_register_event_parameters_t) #define ISCSI_WAIT_EVENT _IOWR(0, 13, iscsi_wait_event_parameters_t) #define ISCSI_POLL_EVENT _IOWR(0, 14, iscsi_wait_event_parameters_t) +#define ISCSI_LOGIN _IOWR(0, 15, iscsi_login_parameters_t) #endif /* !_ISCSI_IOCTL_H */ Index: sys/dev/iscsi/iscsi_text.c =================================================================== RCS file: /cvsroot/src/sys/dev/iscsi/iscsi_text.c,v retrieving revision 1.14 diff -p -u -r1.14 iscsi_text.c --- sys/dev/iscsi/iscsi_text.c 25 Nov 2023 10:08:27 -0000 1.14 +++ sys/dev/iscsi/iscsi_text.c 28 Dec 2023 21:00:58 -0000 @@ -31,6 +31,7 @@ #include "iscsi_globals.h" #include "base64.h" +#include #include #include @@ -133,7 +134,7 @@ typedef struct STATIC key_entry_t entries[] = { {"AuthMethod", T_AUTH, 0}, - {"CHAP_A", T_NUM, ISCSI_CHAP_MD5}, + {"CHAP_A", T_STRING, ISCSI_CHAP_MD5}, {"CHAP_C", T_BIGNUM, 0}, {"CHAP_I", T_NUM, 0}, {"CHAP_N", T_STRING, 0}, @@ -197,7 +198,9 @@ typedef struct uint8_t password[MAX_STRING + 1]; /* authentication secret */ uint8_t target_password[MAX_STRING + 1]; /* target authentication secret */ uint8_t user_name[MAX_STRING + 1]; /* authentication user ID */ + uint8_t target_user_name[MAX_STRING + 1]; /* target authentication user */ uint8_t temp_buf[MAX_STRING + 1]; /* scratch buffer */ + uint64_t chap_algorithms[4]; bool HeaderDigest; bool DataDigest; @@ -594,6 +597,128 @@ get_parameter(uint8_t *buf, negotiation_ /*****************************************************************************/ +STATIC void +chap_algo_mask_zero(uint64_t mask[4]) +{ + mask[0] = 0; + mask[1] = 0; + mask[2] = 0; + mask[3] = 0; +} + +STATIC void +chap_algo_mask_set(uint64_t mask[4], int val) +{ + if (val >= 0 && val < 256) + mask[val / 64] |= (uint64_t)1 << (val % 64); +} + +STATIC void +chap_algo_mask_clear(uint64_t mask[4], int val) +{ + if (val >= 0 && val < 256) + mask[val / 64] &= ~ ((uint64_t)1 << (val % 64)); +} + +STATIC void +chap_algo_mask_or(uint64_t mask[4], uint64_t val[4]) +{ + mask[0] |= val[0]; + mask[1] |= val[1]; + mask[2] |= val[2]; + mask[3] |= val[3]; +} + +STATIC void +chap_algo_mask_and(uint64_t mask[4], uint64_t val[4]) +{ + mask[0] &= val[0]; + mask[1] &= val[1]; + mask[2] &= val[2]; + mask[3] &= val[3]; +} + +STATIC int +chap_algo_mask_match(uint64_t mask[4], uint64_t val[4]) +{ + if (mask[0] & val[0]) + return 1; + if (mask[1] & val[1]) + return 1; + if (mask[2] & val[2]) + return 1; + if (mask[3] & val[3]) + return 1; + return 0; +} + +STATIC int +chap_algo_mask_first(uint64_t mask[4]) +{ + int val; + + val = ffs64(mask[3]); + if (val) + return 192-1 + val; + val = ffs64(mask[2]); + if (val) + return 128-1 + val; + val = ffs64(mask[1]); + if (val) + return 64-1 + val; + val = ffs64(mask[0]); + return -1 + val; +} + +STATIC void +chap_algo_mask(uint8_t *str, uint64_t mask[4]) +{ + uint32_t val; + uint8_t *end; + + chap_algo_mask_zero(mask); + while (*str) { + end = get_numval(str, &val, ','); + if (end == NULL) + break; + chap_algo_mask_set(mask, val); + str = end; + } +} + +STATIC uint8_t * +chap_algo_string(uint64_t mask[4]) +{ + static char res[916], *p; + size_t sz; + int n, algo; + const char *sep; + uint64_t val[4]; + + val[0] = mask[0]; + val[1] = mask[1]; + val[2] = mask[2]; + val[3] = mask[3]; + + sz = sizeof(res); + p = res; + sep = ""; + while ((algo = chap_algo_mask_first(val)) >= 0) { + chap_algo_mask_clear(val, algo); + n = snprintf(p, sz, "%s%u", sep, algo); + if (n >= sz) + break; + sep = ","; + p += n; + sz -= n; + } + *p++ = '\0'; + + return (uint8_t *)res; +} + +/*****************************************************************************/ + /* * my_strcpy: * Replacement for strcpy that returns the end of the result string @@ -1274,6 +1399,15 @@ assemble_login_parameters(connection_t * else strlcpy(state->user_name, iscsi_InitiatorName, sizeof(state->user_name)); + if (par->is_present.target_user_name) + copyinstr(par->target_user_name, state->target_user_name, + MAX_STRING, &sz); + + /* MD5 is mandatory */ + chap_algo_mask_zero(state->chap_algorithms); + chap_algo_mask_set(state->chap_algorithms, ISCSI_CHAP_MD5); + if (par->is_present.chap_algorithms) + chap_algo_mask_or(state->chap_algorithms, par->chap_algorithms); next = TRUE; @@ -1348,7 +1482,11 @@ assemble_security_parameters(connection_ int challenge_size = 0; uint8_t *response = NULL; int response_size = 0; + uint8_t *chapname = NULL; + int chapname_size = 0; bool challenge_hex = iscsi_hex_bignums; + uint64_t mask[4]; + uint8_t *algorithms; state->num_pars = 0; next = 0; @@ -1391,12 +1529,31 @@ assemble_security_parameters(connection_ break; case K_Auth_CHAP_Algorithm: - if (state->auth_state != AUTH_CHAP_ALG_SENT || - rxp.val.nval[0] != ISCSI_CHAP_MD5) { + if (state->auth_state != AUTH_CHAP_ALG_SENT + || !rxp.list_num) { DEBOUT(("Bad algorithm, auth_state = %d, alg %d\n", state->auth_state, rxp.val.nval[0])); return ISCSI_STATUS_NEGOTIATION_ERROR; } + chap_algo_mask(rxp.val.sval, mask); + if (!chap_algo_mask_match(state->chap_algorithms, mask)) { + DEBOUT(("Unmatched algorithm, auth_state = %d\n" + " I: %016"PRIx64".%016"PRIx64".%016"PRIx64".%016"PRIx64"\n" + " T: %016"PRIx64".%016"PRIx64".%016"PRIx64".%016"PRIx64"\n", + state->auth_state, + state->chap_algorithms[0], + state->chap_algorithms[1], + state->chap_algorithms[2], + state->chap_algorithms[3], + mask[0], + mask[1], + mask[2], + mask[3] + )); + return ISCSI_STATUS_NEGOTIATION_ERROR; + } + DEBOUT(("CHAP Algorithm masking %s\n", rxp.val.sval)); + chap_algo_mask_and(state->chap_algorithms, mask); break; case K_Auth_CHAP_Challenge: @@ -1426,7 +1583,10 @@ assemble_security_parameters(connection_ state->auth_state, rxp.val.sval)); return ISCSI_STATUS_NEGOTIATION_ERROR; } - /* what do we do with the name?? */ + if (rxp.list_num > 0) { + chapname = rxp.val.sval; + chapname_size = rxp.list_num; + } break; case K_Auth_CHAP_Response: @@ -1458,7 +1618,9 @@ assemble_security_parameters(connection_ return ISCSI_STATUS_NEGOTIATION_ERROR; case AUTH_METHOD_SELECTED: - set_key_n(state, K_Auth_CHAP_Algorithm, ISCSI_CHAP_MD5); + algorithms = chap_algo_string(state->chap_algorithms); + if (algorithms != NULL) + set_key_s(state, K_Auth_CHAP_Algorithm, algorithms); state->auth_state = AUTH_CHAP_ALG_SENT; next = -1; break; @@ -1473,8 +1635,15 @@ assemble_security_parameters(connection_ set_key_s(state, K_Auth_CHAP_Name, state->user_name); - chap_md5_response(state->temp_buf, identifier, - state->password, challenge, challenge_size); + switch (chap_algo_mask_first(state->chap_algorithms)) { + case ISCSI_CHAP_MD5: + chap_md5_response(state->temp_buf, identifier, + state->password, challenge, challenge_size); + break; + default: + DEBOUT(("Invalid CHAP algorithm\n")); + return ISCSI_STATUS_NEGOTIATION_ERROR; + } cpar = set_key_s(state, K_Auth_CHAP_Response, state->temp_buf); if (cpar != NULL) { @@ -1515,11 +1684,27 @@ assemble_security_parameters(connection_ return ISCSI_STATUS_NEGOTIATION_ERROR; } - chap_md5_response(state->temp_buf, - state->temp_buf[CHAP_MD5_SIZE], - state->target_password, - &state->temp_buf[CHAP_MD5_SIZE + 1], - CHAP_CHALLENGE_LEN); + switch (chap_algo_mask_first(state->chap_algorithms)) { + case ISCSI_CHAP_MD5: + chap_md5_response(state->temp_buf, + state->temp_buf[CHAP_MD5_SIZE], + state->target_password, + &state->temp_buf[CHAP_MD5_SIZE + 1], + CHAP_CHALLENGE_LEN); + break; + default: + DEBOUT(("Mutual authentication invalid algorithm\n")); + return ISCSI_STATUS_AUTHENTICATION_FAILED; + } + + if (state->target_user_name[0] && ( + chapname == NULL || + chapname_size > sizeof(state->target_user_name) || + memcmp(state->target_user_name, chapname, chapname_size) + )) { + DEBOUT(("Mutual authentication mismatch\n")); + return ISCSI_STATUS_AUTHENTICATION_FAILED; + } if (response_size > sizeof(state->temp_buf) || memcmp(state->temp_buf, response, response_size)) { Index: sbin/iscsid/iscsid.h =================================================================== RCS file: /cvsroot/src/sbin/iscsid/iscsid.h,v retrieving revision 1.5 diff -p -u -r1.5 iscsid.h --- sbin/iscsid/iscsid.h 29 May 2016 13:35:45 -0000 1.5 +++ sbin/iscsid/iscsid.h 28 Dec 2023 21:00:58 -0000 @@ -353,6 +353,7 @@ typedef struct { iscsi_auth_info_t auth_info; uint8_t user_name[ISCSI_STRING_LENGTH]; uint8_t password[ISCSI_STRING_LENGTH]; + uint8_t target_user_name[ISCSI_STRING_LENGTH]; uint8_t target_password[ISCSI_STRING_LENGTH]; } iscsid_set_target_authentication_req_t; Index: sbin/iscsictl/iscsic_parse.c =================================================================== RCS file: /cvsroot/src/sbin/iscsictl/iscsic_parse.c,v retrieving revision 1.5 diff -p -u -r1.5 iscsic_parse.c --- sbin/iscsictl/iscsic_parse.c 25 Nov 2023 08:06:02 -0000 1.5 +++ sbin/iscsictl/iscsic_parse.c 28 Dec 2023 21:00:58 -0000 @@ -398,6 +398,10 @@ cl_get_auth_opts(iscsid_set_target_authe get_str((char *)auth->password, sp, argv[i], "Secret"); break; + case 'U': /* target user name */ + get_str((char *)auth->target_user_name, sp, argv[i], "Target user name"); + break; + case 'S': /* target secret */ get_str((char *)auth->target_password, sp, argv[i], "Target secret"); break; Index: sbin/iscsictl/iscsictl.8 =================================================================== RCS file: /cvsroot/src/sbin/iscsictl/iscsictl.8,v retrieving revision 1.9 diff -p -u -r1.9 iscsictl.8 --- sbin/iscsictl/iscsictl.8 30 Aug 2015 10:49:57 -0000 1.9 +++ sbin/iscsictl/iscsictl.8 28 Dec 2023 21:00:58 -0000 @@ -150,9 +150,11 @@ indicates CHAP authentication, and .Ar C indicates Mutual CHAP authentication. .It Fl u Ar name -User name. +Initiator user name. .It Fl s Ar secret Initiator secret. +.It Fl U Ar name +Target user name. .It Fl S Ar secret Target secret. .El