diff --git a/lib/iscsi/conn.c b/lib/iscsi/conn.c index f0392f631..7f29c9c00 100644 --- a/lib/iscsi/conn.c +++ b/lib/iscsi/conn.c @@ -403,10 +403,6 @@ static void spdk_iscsi_conn_free(struct spdk_iscsi_conn *conn) */ spdk_put_pdu(conn->pdu_in_progress); - free(conn->auth.user); - free(conn->auth.secret); - free(conn->auth.muser); - free(conn->auth.msecret); free_conn(conn); } diff --git a/lib/iscsi/iscsi.c b/lib/iscsi/iscsi.c index 08c0f5544..1f40c5e14 100644 --- a/lib/iscsi/iscsi.c +++ b/lib/iscsi/iscsi.c @@ -71,6 +71,7 @@ struct spdk_iscsi_globals g_spdk_iscsi = { .pg_head = TAILQ_HEAD_INITIALIZER(g_spdk_iscsi.pg_head), .ig_head = TAILQ_HEAD_INITIALIZER(g_spdk_iscsi.ig_head), .target_head = TAILQ_HEAD_INITIALIZER(g_spdk_iscsi.target_head), + .auth_group_head = TAILQ_HEAD_INITIALIZER(g_spdk_iscsi.auth_group_head), }; /* random value generation */ @@ -679,7 +680,6 @@ spdk_iscsi_append_param(struct spdk_iscsi_conn *conn, const char *key, static int spdk_iscsi_get_authinfo(struct spdk_iscsi_conn *conn, const char *authuser) { - char *authfile = NULL; int ag_tag; int rc; @@ -693,21 +693,11 @@ spdk_iscsi_get_authinfo(struct spdk_iscsi_conn *conn, const char *authuser) } SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "ag_tag=%d\n", ag_tag); - pthread_mutex_lock(&g_spdk_iscsi.mutex); - authfile = strdup(g_spdk_iscsi.authfile); - pthread_mutex_unlock(&g_spdk_iscsi.mutex); - if (!authfile) { - SPDK_ERRLOG("strdup() failed for authfile\n"); - return -ENOMEM; - } - - rc = spdk_iscsi_chap_get_authinfo(&conn->auth, authfile, authuser, ag_tag); + rc = spdk_iscsi_chap_get_authinfo(&conn->auth, authuser, ag_tag); if (rc < 0) { SPDK_ERRLOG("chap_get_authinfo() failed\n"); - free(authfile); return -1; } - free(authfile); return 0; } @@ -829,7 +819,7 @@ spdk_iscsi_auth_params(struct spdk_iscsi_conn *conn, SPDK_ERRLOG("iscsi_get_authinfo() failed\n"); goto error_return; } - if (conn->auth.user == NULL || conn->auth.secret == NULL) { + if (conn->auth.user[0] == '\0' || conn->auth.secret[0] == '\0') { //SPDK_ERRLOG("auth user or secret is missing\n"); SPDK_ERRLOG("auth failed (user %.64s)\n", user); goto error_return; @@ -889,7 +879,7 @@ spdk_iscsi_auth_params(struct spdk_iscsi_conn *conn, #endif SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "got CHAP_I/CHAP_C\n"); - if (conn->auth.muser == NULL || conn->auth.msecret == NULL) { + if (conn->auth.muser[0] == '\0' || conn->auth.msecret[0] == '\0') { //SPDK_ERRLOG("mutual auth user or secret is missing\n"); SPDK_ERRLOG("auth failed (user %.64s)\n", user); goto error_return; diff --git a/lib/iscsi/iscsi.h b/lib/iscsi/iscsi.h index 249aa866b..88b4cf301 100644 --- a/lib/iscsi/iscsi.h +++ b/lib/iscsi/iscsi.h @@ -220,14 +220,17 @@ enum session_type { SESSION_TYPE_DISCOVERY = 2, }; -#define ISCSI_CHAP_CHALLENGE_LEN 1024 +#define ISCSI_CHAP_CHALLENGE_LEN 1024 +#define ISCSI_CHAP_MAX_USER_LEN 255 +#define ISCSI_CHAP_MAX_SECRET_LEN 255 + struct iscsi_chap_auth { enum iscsi_chap_phase chap_phase; - char *user; - char *secret; - char *muser; - char *msecret; + char user[ISCSI_CHAP_MAX_USER_LEN + 1]; + char secret[ISCSI_CHAP_MAX_SECRET_LEN + 1]; + char muser[ISCSI_CHAP_MAX_USER_LEN + 1]; + char msecret[ISCSI_CHAP_MAX_SECRET_LEN + 1]; uint8_t chap_id[1]; uint8_t chap_mid[1]; @@ -237,6 +240,20 @@ struct iscsi_chap_auth { uint8_t chap_mchallenge[ISCSI_CHAP_CHALLENGE_LEN]; }; +struct spdk_iscsi_auth_secret { + char user[ISCSI_CHAP_MAX_USER_LEN + 1]; + char secret[ISCSI_CHAP_MAX_SECRET_LEN + 1]; + char muser[ISCSI_CHAP_MAX_USER_LEN + 1]; + char msecret[ISCSI_CHAP_MAX_SECRET_LEN + 1]; + TAILQ_ENTRY(spdk_iscsi_auth_secret) tailq; +}; + +struct spdk_iscsi_auth_group { + int32_t tag; + TAILQ_HEAD(, spdk_iscsi_auth_secret) secret_head; + TAILQ_ENTRY(spdk_iscsi_auth_group) tailq; +}; + struct spdk_iscsi_sess { uint32_t connections; struct spdk_iscsi_conn **conns; @@ -308,6 +325,7 @@ struct spdk_iscsi_globals { TAILQ_HEAD(, spdk_iscsi_portal_grp) pg_head; TAILQ_HEAD(, spdk_iscsi_init_grp) ig_head; TAILQ_HEAD(, spdk_iscsi_tgt_node) target_head; + TAILQ_HEAD(, spdk_iscsi_auth_group) auth_group_head; int32_t timeout; int32_t nopininterval; @@ -381,8 +399,8 @@ struct spdk_iscsi_opts *spdk_iscsi_opts_copy(struct spdk_iscsi_opts *src); void spdk_iscsi_opts_info_json(struct spdk_json_write_ctx *w); int spdk_iscsi_set_discovery_auth(bool disable_chap, bool require_chap, bool mutual_chap, int32_t chap_group); -int spdk_iscsi_chap_get_authinfo(struct iscsi_chap_auth *auth, const char *authfile, - const char *authuser, int ag_tag); +int spdk_iscsi_chap_get_authinfo(struct iscsi_chap_auth *auth, const char *authuser, + int ag_tag); void spdk_iscsi_send_nopin(struct spdk_iscsi_conn *conn); void spdk_iscsi_task_response(struct spdk_iscsi_conn *conn, diff --git a/lib/iscsi/iscsi_subsystem.c b/lib/iscsi/iscsi_subsystem.c index 91c2b4d44..4eb82da1d 100644 --- a/lib/iscsi/iscsi_subsystem.c +++ b/lib/iscsi/iscsi_subsystem.c @@ -801,85 +801,212 @@ spdk_iscsi_set_discovery_auth(bool disable_chap, bool require_chap, bool mutual_ return 0; } -int -spdk_iscsi_chap_get_authinfo(struct iscsi_chap_auth *auth, const char *authfile, - const char *authuser, int ag_tag) +static int +spdk_iscsi_auth_group_add_secret(struct spdk_iscsi_auth_group *group, + const char *user, const char *secret, + const char *muser, const char *msecret) +{ + struct spdk_iscsi_auth_secret *_secret; + size_t len; + + if (user == NULL || secret == NULL) { + SPDK_ERRLOG("user and secret must be specified\n"); + return -EINVAL; + } + + if (muser != NULL && msecret == NULL) { + SPDK_ERRLOG("msecret must be specified with muser\n"); + return -EINVAL; + } + + TAILQ_FOREACH(_secret, &group->secret_head, tailq) { + if (strcmp(_secret->user, user) == 0) { + SPDK_ERRLOG("user for secret is duplicated\n"); + return -EEXIST; + } + } + + _secret = calloc(1, sizeof(*_secret)); + if (_secret == NULL) { + SPDK_ERRLOG("calloc() failed for CHAP secret\n"); + return -ENOMEM; + } + + len = strnlen(user, sizeof(_secret->user)); + if (len > sizeof(_secret->user) - 1) { + SPDK_ERRLOG("CHAP user longer than %zu characters: %s\n", + sizeof(_secret->user) - 1, user); + free(_secret); + return -EINVAL; + } + memcpy(_secret->user, user, len); + + len = strnlen(secret, sizeof(_secret->secret)); + if (len > sizeof(_secret->secret) - 1) { + SPDK_ERRLOG("CHAP secret longer than %zu characters: %s\n", + sizeof(_secret->secret) - 1, secret); + free(_secret); + return -EINVAL; + } + memcpy(_secret->secret, secret, len); + + if (muser != NULL) { + len = strnlen(muser, sizeof(_secret->muser)); + if (len > sizeof(_secret->muser) - 1) { + SPDK_ERRLOG("Mutual CHAP user longer than %zu characters: %s\n", + sizeof(_secret->muser) - 1, muser); + free(_secret); + return -EINVAL; + } + memcpy(_secret->muser, muser, len); + + len = strnlen(msecret, sizeof(_secret->msecret)); + if (len > sizeof(_secret->msecret) - 1) { + SPDK_ERRLOG("Mutual CHAP secret longer than %zu characters: %s\n", + sizeof(_secret->msecret) - 1, msecret); + free(_secret); + return -EINVAL; + } + memcpy(_secret->msecret, msecret, len); + } + + TAILQ_INSERT_TAIL(&group->secret_head, _secret, tailq); + return 0; +} + +static int +spdk_iscsi_add_auth_group(int32_t tag, struct spdk_iscsi_auth_group **_group) +{ + struct spdk_iscsi_auth_group *group; + + TAILQ_FOREACH(group, &g_spdk_iscsi.auth_group_head, tailq) { + if (group->tag == tag) { + SPDK_ERRLOG("Auth group (%d) already exists\n", tag); + return -EEXIST; + } + } + + group = calloc(1, sizeof(*group)); + if (group == NULL) { + SPDK_ERRLOG("calloc() failed for auth group\n"); + return -ENOMEM; + } + + TAILQ_INIT(&group->secret_head); + group->tag = tag; + + TAILQ_INSERT_TAIL(&g_spdk_iscsi.auth_group_head, group, tailq); + + *_group = group; + return 0; +} + +static void +spdk_iscsi_delete_auth_group(struct spdk_iscsi_auth_group *group) +{ + struct spdk_iscsi_auth_secret *_secret, *tmp; + + TAILQ_REMOVE(&g_spdk_iscsi.auth_group_head, group, tailq); + + TAILQ_FOREACH_SAFE(_secret, &group->secret_head, tailq, tmp) { + TAILQ_REMOVE(&group->secret_head, _secret, tailq); + free(_secret); + } + free(group); +} + +static void +spdk_iscsi_auth_groups_destroy(void) +{ + struct spdk_iscsi_auth_group *group, *tmp; + + TAILQ_FOREACH_SAFE(group, &g_spdk_iscsi.auth_group_head, tailq, tmp) { + spdk_iscsi_delete_auth_group(group); + } +} + +static int +spdk_iscsi_parse_auth_group(struct spdk_conf_section *sp) { - struct spdk_conf *config = NULL; - struct spdk_conf_section *sp; - const char *val; - const char *user, *muser; - const char *secret, *msecret; int rc; int i; + int tag; + const char *val, *user, *secret, *muser, *msecret; + struct spdk_iscsi_auth_group *group = NULL; - if (auth->user != NULL) { - free(auth->user); - free(auth->secret); - free(auth->muser); - free(auth->msecret); - auth->user = auth->secret = NULL; - auth->muser = auth->msecret = NULL; + val = spdk_conf_section_get_val(sp, "Comment"); + if (val != NULL) { + SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "Comment %s\n", val); } - /* read config files */ + tag = spdk_conf_section_get_num(sp); + + rc = spdk_iscsi_add_auth_group(tag, &group); + if (rc != 0) { + SPDK_ERRLOG("Failed to add auth group\n"); + return rc; + } + + for (i = 0; ; i++) { + val = spdk_conf_section_get_nval(sp, "Auth", i); + if (val == NULL) { + break; + } + + user = spdk_conf_section_get_nmval(sp, "Auth", i, 0); + secret = spdk_conf_section_get_nmval(sp, "Auth", i, 1); + muser = spdk_conf_section_get_nmval(sp, "Auth", i, 2); + msecret = spdk_conf_section_get_nmval(sp, "Auth", i, 3); + + rc = spdk_iscsi_auth_group_add_secret(group, user, secret, muser, msecret); + if (rc != 0) { + SPDK_ERRLOG("Failed to add secret to auth group\n"); + spdk_iscsi_delete_auth_group(group); + return rc; + } + } + + return 0; +} + +static int +spdk_iscsi_parse_auth_info(void) +{ + struct spdk_conf *config; + struct spdk_conf_section *sp; + int rc; + config = spdk_conf_allocate(); - if (config == NULL) { - SPDK_ERRLOG("allocate config fail\n"); - return -1; + if (!config) { + SPDK_ERRLOG("Failed to allocate config file\n"); + return -ENOMEM; } - rc = spdk_conf_read(config, authfile); - if (rc < 0) { - SPDK_ERRLOG("auth conf error\n"); + rc = spdk_conf_read(config, g_spdk_iscsi.authfile); + if (rc != 0) { + SPDK_INFOLOG(SPDK_LOG_ISCSI, "Failed to load auth file\n"); spdk_conf_free(config); - return -1; + return rc; } - //spdk_conf_print(config); sp = spdk_conf_first_section(config); while (sp != NULL) { if (spdk_conf_section_match_prefix(sp, "AuthGroup")) { - int group = spdk_conf_section_get_num(sp); - if (group == 0) { + if (spdk_conf_section_get_num(sp) == 0) { SPDK_ERRLOG("Group 0 is invalid\n"); + spdk_iscsi_auth_groups_destroy(); spdk_conf_free(config); - return -1; - } - if (ag_tag != group) { - goto skip_ag_tag; + return -EINVAL; } - val = spdk_conf_section_get_val(sp, "Comment"); - if (val != NULL) { - SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "Comment %s\n", val); - } - for (i = 0; ; i++) { - val = spdk_conf_section_get_nval(sp, "Auth", i); - if (val == NULL) { - break; - } - user = spdk_conf_section_get_nmval(sp, "Auth", i, 0); - secret = spdk_conf_section_get_nmval(sp, "Auth", i, 1); - muser = spdk_conf_section_get_nmval(sp, "Auth", i, 2); - msecret = spdk_conf_section_get_nmval(sp, "Auth", i, 3); - if (user != NULL) { - if (strcasecmp(authuser, user) == 0) { - /* match user */ - auth->user = xstrdup(user); - auth->secret = xstrdup(secret); - auth->muser = xstrdup(muser); - auth->msecret = xstrdup(msecret); - spdk_conf_free(config); - return 0; - } - } else { - SPDK_ERRLOG("Invalid Auth format, skip this line\n"); - continue; - } + rc = spdk_iscsi_parse_auth_group(sp); + if (rc != 0) { + SPDK_ERRLOG("parse_auth_group() failed\n"); + spdk_iscsi_auth_groups_destroy(); + spdk_conf_free(config); + return rc; } } -skip_ag_tag: sp = spdk_conf_next_section(sp); } @@ -887,6 +1014,60 @@ skip_ag_tag: return 0; } +static struct spdk_iscsi_auth_secret * +spdk_iscsi_find_auth_secret(const char *authuser, int ag_tag) +{ + struct spdk_iscsi_auth_group *group; + struct spdk_iscsi_auth_secret *_secret; + + TAILQ_FOREACH(group, &g_spdk_iscsi.auth_group_head, tailq) { + if (group->tag == ag_tag) { + TAILQ_FOREACH(_secret, &group->secret_head, tailq) { + if (strcmp(_secret->user, authuser) == 0) { + return _secret; + } + } + } + } + + return NULL; +} + +int +spdk_iscsi_chap_get_authinfo(struct iscsi_chap_auth *auth, const char *authuser, + int ag_tag) +{ + struct spdk_iscsi_auth_secret *_secret; + + if (authuser == NULL) { + return -EINVAL; + } + + if (auth->user[0] != '\0') { + memset(auth->user, 0, sizeof(auth->user)); + memset(auth->secret, 0, sizeof(auth->secret)); + memset(auth->muser, 0, sizeof(auth->muser)); + memset(auth->msecret, 0, sizeof(auth->msecret)); + } + + _secret = spdk_iscsi_find_auth_secret(authuser, ag_tag); + if (_secret == NULL) { + SPDK_ERRLOG("CHAP secret is not found: user:%s, tag:%d\n", + authuser, ag_tag); + return -ENOENT; + } + + memcpy(auth->user, _secret->user, sizeof(auth->user)); + memcpy(auth->secret, _secret->secret, sizeof(auth->secret)); + + if (_secret->muser[0] != '\0') { + memcpy(auth->muser, _secret->muser, sizeof(auth->muser)); + memcpy(auth->msecret, _secret->msecret, sizeof(auth->msecret)); + } + + return 0; +} + static int spdk_iscsi_initialize_global_params(void) { @@ -1032,6 +1213,16 @@ spdk_iscsi_parse_configuration(void *ctx) SPDK_ERRLOG("spdk_iscsi_parse_tgt_nodes() failed\n"); } + if (access(g_spdk_iscsi.authfile, R_OK) == 0) { + rc = spdk_iscsi_parse_auth_info(); + if (rc < 0) { + SPDK_ERRLOG("spdk_iscsi_parse_auth_info() failed\n"); + } + } else { + SPDK_INFOLOG(SPDK_LOG_ISCSI, "CHAP secret file is not found in the path %s\n", + g_spdk_iscsi.authfile); + } + end: spdk_iscsi_init_complete(rc); } @@ -1118,6 +1309,7 @@ spdk_iscsi_fini_done(void *arg) spdk_iscsi_shutdown_tgt_nodes(); spdk_iscsi_init_grps_destroy(); spdk_iscsi_portal_grps_destroy(); + spdk_iscsi_auth_groups_destroy(); free(g_spdk_iscsi.authfile); free(g_spdk_iscsi.nodebase); free(g_spdk_iscsi.poll_group); diff --git a/test/unit/lib/iscsi/iscsi.c/iscsi_ut.c b/test/unit/lib/iscsi/iscsi.c/iscsi_ut.c index 7d46b09d1..7c9f76cb8 100644 --- a/test/unit/lib/iscsi/iscsi.c/iscsi_ut.c +++ b/test/unit/lib/iscsi/iscsi.c/iscsi_ut.c @@ -97,8 +97,8 @@ spdk_iscsi_conn_free_pdu(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pd } int -spdk_iscsi_chap_get_authinfo(struct iscsi_chap_auth *auth, const char *authfile, - const char *authuser, int ag_tag) +spdk_iscsi_chap_get_authinfo(struct iscsi_chap_auth *auth, const char *authuser, + int ag_tag) { return 0; }