diff --git a/CHANGELOG.md b/CHANGELOG.md index f5f748a3f..605cdf87a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,8 +29,9 @@ method for CHAP authentication in discovery sessions have been changed to align with `construct_target_node` RPC method. Old names are still usable but will be removed in future release. -`set_iscsi_discovery_auth` RPC method has been added to set CHAP authentication -for discovery sessions dynamically. +`set_iscsi_discovery_auth` and `set_iscsi_target_node_auth` RPC methods have +been added to set CHAP authentication for discovery sessions and existing +target nodes, respectively. ## v18.07: diff --git a/doc/jsonrpc.md b/doc/jsonrpc.md index c2bf4c582..2c9d91a49 100644 --- a/doc/jsonrpc.md +++ b/doc/jsonrpc.md @@ -2184,6 +2184,8 @@ chap_group | Optional | number | Authentication group ID for t header_digest | Optional | boolean | Header Digest should be required for this target node data_digest | Optional | boolean | Data Digest should be required for this target node +Parameters `disable_chap` and `require_chap` are mutually exclusive. + ### Example Example request: @@ -2231,6 +2233,50 @@ Example response: } ~~~ +## set_iscsi_target_node_auth method {#rpc_set_iscsi_target_node_auth} + +Set CHAP authentication to an existing iSCSI target node. + +### Parameters + +Name | Optional | Type | Description +--------------------------- | -------- | --------| ----------- +name | Required | string | Target node name (ASCII) +disable_chap | Optional | boolean | CHAP authentication should be disabled for this target +require_chap | Optional | boolean | CHAP authentication should be required for this target +mutual_chap | Optional | boolean | CHAP authentication should be bidirectional (`true`) or unidirectional (`false`) +chap_group | Optional | number | Authentication group ID for this target node + +Parameters `disable_chap` and `require_chap` are mutually exclusive. + +### Example + +Example request: + +~~~ +{ + "params": { + "chap_group": 1, + "require_chap": true, + "name": "iqn.2016-06.io.spdk:target1", + "mutual_chap": true + }, + "jsonrpc": "2.0", + "method": "set_iscsi_target_node_auth", + "id": 1 +} +~~~ + +Example response: + +~~~ +{ + "jsonrpc": "2.0", + "id": 1, + "result": true +} +~~~ + ## add_pg_ig_maps method {#rpc_add_pg_ig_maps} Add initiator group to portal group mappings to an existing iSCSI target node. diff --git a/lib/iscsi/iscsi_rpc.c b/lib/iscsi/iscsi_rpc.c index 082e581fd..15428265f 100644 --- a/lib/iscsi/iscsi_rpc.c +++ b/lib/iscsi/iscsi_rpc.c @@ -1035,6 +1035,75 @@ invalid: } SPDK_RPC_REGISTER("target_node_add_lun", spdk_rpc_target_node_add_lun, SPDK_RPC_RUNTIME) +struct rpc_target_auth { + char *name; + bool disable_chap; + bool require_chap; + bool mutual_chap; + int32_t chap_group; +}; + +static void +free_rpc_target_auth(struct rpc_target_auth *req) +{ + free(req->name); +} + +static const struct spdk_json_object_decoder rpc_target_auth_decoders[] = { + {"name", offsetof(struct rpc_target_auth, name), spdk_json_decode_string}, + {"disable_chap", offsetof(struct rpc_target_auth, disable_chap), spdk_json_decode_bool, true}, + {"require_chap", offsetof(struct rpc_target_auth, require_chap), spdk_json_decode_bool, true}, + {"mutual_chap", offsetof(struct rpc_target_auth, mutual_chap), spdk_json_decode_bool, true}, + {"chap_group", offsetof(struct rpc_target_auth, chap_group), spdk_json_decode_int32, true}, +}; + +static void +spdk_rpc_set_iscsi_target_node_auth(struct spdk_jsonrpc_request *request, + const struct spdk_json_val *params) +{ + struct rpc_target_auth req = {}; + struct spdk_json_write_ctx *w; + struct spdk_iscsi_tgt_node *target; + int rc; + + if (spdk_json_decode_object(params, rpc_target_auth_decoders, + SPDK_COUNTOF(rpc_target_auth_decoders), &req)) { + SPDK_ERRLOG("spdk_json_decode_object failed\n"); + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, + "Invalid parameters"); + return; + } + + target = spdk_iscsi_find_tgt_node(req.name); + if (target == NULL) { + spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, + "Could not find target %s", req.name); + free_rpc_target_auth(&req); + return; + } + + rc = spdk_iscsi_tgt_node_set_chap_params(target, req.disable_chap, req.require_chap, + req.mutual_chap, req.chap_group); + if (rc < 0) { + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, + "Invalid combination of CHAP params"); + free_rpc_target_auth(&req); + return; + } + + free_rpc_target_auth(&req); + + w = spdk_jsonrpc_begin_result(request); + if (w == NULL) { + return; + } + + spdk_json_write_bool(w, true); + spdk_jsonrpc_end_result(request, w); +} +SPDK_RPC_REGISTER("set_iscsi_target_node_auth", spdk_rpc_set_iscsi_target_node_auth, + SPDK_RPC_RUNTIME) + static void spdk_rpc_get_iscsi_global_params(struct spdk_jsonrpc_request *request, const struct spdk_json_val *params) diff --git a/lib/iscsi/tgt_node.c b/lib/iscsi/tgt_node.c index 403892136..97b5bbe16 100644 --- a/lib/iscsi/tgt_node.c +++ b/lib/iscsi/tgt_node.c @@ -1332,6 +1332,26 @@ spdk_iscsi_tgt_node_add_lun(struct spdk_iscsi_tgt_node *target, return 0; } +int +spdk_iscsi_tgt_node_set_chap_params(struct spdk_iscsi_tgt_node *target, + bool disable_chap, bool require_chap, + bool mutual_chap, int32_t chap_group) +{ + if (!spdk_iscsi_check_chap_params(disable_chap, require_chap, + mutual_chap, chap_group)) { + return -EINVAL; + } + + pthread_mutex_lock(&target->mutex); + target->disable_chap = disable_chap; + target->require_chap = require_chap; + target->mutual_chap = mutual_chap; + target->chap_group = chap_group; + pthread_mutex_unlock(&target->mutex); + + return 0; +} + static const char *target_nodes_section = \ "\n" "# Users should change the TargetNode section(s) below to match the\n" diff --git a/lib/iscsi/tgt_node.h b/lib/iscsi/tgt_node.h index f68f7d67c..1d54922a8 100644 --- a/lib/iscsi/tgt_node.h +++ b/lib/iscsi/tgt_node.h @@ -137,6 +137,9 @@ void spdk_iscsi_tgt_node_delete_map(struct spdk_iscsi_portal_grp *portal_group, struct spdk_iscsi_init_grp *initiator_group); int spdk_iscsi_tgt_node_add_lun(struct spdk_iscsi_tgt_node *target, const char *bdev_name, int lun_id); +int spdk_iscsi_tgt_node_set_chap_params(struct spdk_iscsi_tgt_node *target, + bool disable_chap, bool require_chap, + bool mutual_chap, int32_t chap_group); void spdk_iscsi_tgt_nodes_config_text(FILE *fp); void spdk_iscsi_tgt_nodes_info_json(struct spdk_json_write_ctx *w); void spdk_iscsi_tgt_nodes_config_json(struct spdk_json_write_ctx *w); diff --git a/scripts/rpc.py b/scripts/rpc.py index c06df3d89..44d80c0b0 100755 --- a/scripts/rpc.py +++ b/scripts/rpc.py @@ -644,6 +644,28 @@ if __name__ == "__main__": *** If LUN ID is omitted or -1, the lowest free one is assigned ***""", type=int, required=False) p.set_defaults(func=target_node_add_lun) + @call_cmd + def set_iscsi_target_node_auth(args): + rpc.iscsi.set_iscsi_target_node_auth( + args.client, + name=args.name, + chap_group=args.chap_group, + disable_chap=args.disable_chap, + require_chap=args.require_chap, + mutual_chap=args.mutual_chap) + + p = subparsers.add_parser('set_iscsi_target_node_auth', help='Set CHAP authentication for the target node') + p.add_argument('name', help='Target node name (ASCII)') + p.add_argument('-g', '--chap-group', help="""Authentication group ID for this target node. + *** Authentication group must be precreated ***""", type=int, default=0) + p.add_argument('-d', '--disable-chap', help="""CHAP authentication should be disabled for this target node. + *** Mutually exclusive with --require-chap ***""", action='store_true') + p.add_argument('-r', '--require-chap', help="""CHAP authentication should be required for this target node. + *** Mutually exclusive with --disable-chap ***""", action='store_true') + p.add_argument('-m', '--mutual-chap', help='CHAP authentication should be mutual/bidirectional.', + action='store_true') + p.set_defaults(func=set_iscsi_target_node_auth) + @call_cmd def add_pg_ig_maps(args): pg_ig_maps = [] diff --git a/scripts/rpc/iscsi.py b/scripts/rpc/iscsi.py index 092552217..4d616ffc3 100755 --- a/scripts/rpc/iscsi.py +++ b/scripts/rpc/iscsi.py @@ -215,6 +215,40 @@ def target_node_add_lun(client, name, bdev_name, lun_id=None): return client.call('target_node_add_lun', params) +def set_iscsi_target_node_auth( + client, + name, + chap_group=None, + disable_chap=None, + require_chap=None, + mutual_chap=None): + """Set CHAP authentication for the target node. + + Args: + name: Target node name (ASCII) + chap_group: Authentication group ID for this target node + disable_chap: CHAP authentication should be disabled for this target node + require_chap: CHAP authentication should be required for this target node + mutual_chap: CHAP authentication should be mutual/bidirectional + + Returns: + True or False + """ + params = { + 'name': name, + } + + if chap_group: + params['chap_group'] = chap_group + if disable_chap: + params['disable_chap'] = disable_chap + if require_chap: + params['require_chap'] = require_chap + if mutual_chap: + params['mutual_chap'] = mutual_chap + return client.call('set_iscsi_target_node_auth', params) + + def delete_pg_ig_maps(client, pg_ig_maps, name): """Delete PG-IG maps from the target node.