git: dd3603749cb7 - main - iscsi: Move valid_iscsi_name to libiscsiutil

From: John Baldwin <jhb_at_FreeBSD.org>
Date: Fri, 24 Jan 2025 14:54:39 UTC
The branch main has been updated by jhb:

URL: https://cgit.FreeBSD.org/src/commit/?id=dd3603749cb7f20a628f04d595b105962b21a3d2

commit dd3603749cb7f20a628f04d595b105962b21a3d2
Author:     John Baldwin <jhb@FreeBSD.org>
AuthorDate: 2025-01-24 14:52:10 +0000
Commit:     John Baldwin <jhb@FreeBSD.org>
CommitDate: 2025-01-24 14:53:22 +0000

    iscsi: Move valid_iscsi_name to libiscsiutil
    
    While here, use isxdigit(3) instead of a home-rolled version.
    
    Reviewed by:    mav, asomers
    Sponsored by:   Chelsio Communications
    Differential Revision:  https://reviews.freebsd.org/D48593
---
 lib/libiscsiutil/libiscsiutil.h |   3 ++
 lib/libiscsiutil/utils.c        |  71 ++++++++++++++++++++++++++
 usr.bin/iscsictl/Makefile       |   3 +-
 usr.bin/iscsictl/iscsictl.c     | 107 ++--------------------------------------
 usr.bin/iscsictl/iscsictl.h     |   3 --
 usr.sbin/ctld/ctld.c            | 103 +-------------------------------------
 usr.sbin/ctld/ctld.h            |   2 -
 usr.sbin/ctld/login.c           |   2 +-
 8 files changed, 82 insertions(+), 212 deletions(-)

diff --git a/lib/libiscsiutil/libiscsiutil.h b/lib/libiscsiutil/libiscsiutil.h
index bf26a5b8ed66..8da6ead73fce 100644
--- a/lib/libiscsiutil/libiscsiutil.h
+++ b/lib/libiscsiutil/libiscsiutil.h
@@ -154,6 +154,9 @@ void			text_send_response(struct pdu *request,
 void			connection_init(struct connection *conn,
 			    const struct connection_ops *ops, bool use_proxy);
 
+bool			valid_iscsi_name(const char *name,
+			    void (*warn_fn)(const char *, ...));
+
 void			log_init(int level);
 void			log_set_peer_name(const char *name);
 void			log_set_peer_addr(const char *addr);
diff --git a/lib/libiscsiutil/utils.c b/lib/libiscsiutil/utils.c
index e078c7a53a17..ef2d67106da5 100644
--- a/lib/libiscsiutil/utils.c
+++ b/lib/libiscsiutil/utils.c
@@ -28,10 +28,13 @@
  * SUCH DAMAGE.
  */
 
+#include <ctype.h>
 #include <string.h>
 
 #include "libiscsiutil.h"
 
+#define	MAX_NAME_LEN			223
+
 char *
 checked_strdup(const char *s)
 {
@@ -42,3 +45,71 @@ checked_strdup(const char *s)
 		log_err(1, "strdup");
 	return (c);
 }
+
+bool
+valid_iscsi_name(const char *name, void (*warn_fn)(const char *, ...))
+{
+	int i;
+
+	if (strlen(name) >= MAX_NAME_LEN) {
+		warn_fn("overlong name for target \"%s\"; max length allowed "
+		    "by iSCSI specification is %d characters",
+		    name, MAX_NAME_LEN);
+		return (false);
+	}
+
+	/*
+	 * In the cases below, we don't return an error, just in case the admin
+	 * was right, and we're wrong.
+	 */
+	if (strncasecmp(name, "iqn.", strlen("iqn.")) == 0) {
+		for (i = strlen("iqn."); name[i] != '\0'; i++) {
+			/*
+			 * XXX: We should verify UTF-8 normalisation, as defined
+			 *      by 3.2.6.2: iSCSI Name Encoding.
+			 */
+			if (isalnum(name[i]))
+				continue;
+			if (name[i] == '-' || name[i] == '.' || name[i] == ':')
+				continue;
+			warn_fn("invalid character \"%c\" in target name "
+			    "\"%s\"; allowed characters are letters, digits, "
+			    "'-', '.', and ':'", name[i], name);
+			break;
+		}
+		/*
+		 * XXX: Check more stuff: valid date and a valid reversed domain.
+		 */
+	} else if (strncasecmp(name, "eui.", strlen("eui.")) == 0) {
+		if (strlen(name) != strlen("eui.") + 16)
+			warn_fn("invalid target name \"%s\"; the \"eui.\" "
+			    "should be followed by exactly 16 hexadecimal "
+			    "digits", name);
+		for (i = strlen("eui."); name[i] != '\0'; i++) {
+			if (!isxdigit(name[i])) {
+				warn_fn("invalid character \"%c\" in target "
+				    "name \"%s\"; allowed characters are 1-9 "
+				    "and A-F", name[i], name);
+				break;
+			}
+		}
+	} else if (strncasecmp(name, "naa.", strlen("naa.")) == 0) {
+		if (strlen(name) > strlen("naa.") + 32)
+			warn_fn("invalid target name \"%s\"; the \"naa.\" "
+			    "should be followed by at most 32 hexadecimal "
+			    "digits", name);
+		for (i = strlen("naa."); name[i] != '\0'; i++) {
+			if (!isxdigit(name[i])) {
+				warn_fn("invalid character \"%c\" in target "
+				    "name \"%s\"; allowed characters are 1-9 "
+				    "and A-F", name[i], name);
+				break;
+			}
+		}
+	} else {
+		warn_fn("invalid target name \"%s\"; should start with "
+		    "either \"iqn.\", \"eui.\", or \"naa.\"",
+		    name);
+	}
+	return (true);
+}
diff --git a/usr.bin/iscsictl/Makefile b/usr.bin/iscsictl/Makefile
index 6c09faa3d915..c47b28e7be5e 100644
--- a/usr.bin/iscsictl/Makefile
+++ b/usr.bin/iscsictl/Makefile
@@ -3,9 +3,10 @@ PROG=		iscsictl
 SRCS=		iscsictl.c periphs.c parse.y token.l y.tab.h
 CFLAGS+=	-I${.CURDIR}
 CFLAGS+=	-I${SRCTOP}/sys/dev/iscsi
+CFLAGS+=	-I${SRCTOP}/lib/libiscsiutil
 MAN=		iscsi.conf.5 iscsictl.8
 
-LIBADD=		util xo
+LIBADD=		iscsiutil util xo
 
 YFLAGS+=	-v
 LFLAGS+=	-i
diff --git a/usr.bin/iscsictl/iscsictl.c b/usr.bin/iscsictl/iscsictl.c
index 922e9ed9ebea..f78e47d226bf 100644
--- a/usr.bin/iscsictl/iscsictl.c
+++ b/usr.bin/iscsictl/iscsictl.c
@@ -42,6 +42,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <libiscsiutil.h>
 #include <libxo/xo.h>
 
 #include <iscsi_ioctl.h>
@@ -122,38 +123,6 @@ default_initiator_name(void)
 	return (name);
 }
 
-static bool
-valid_hex(const char ch)
-{
-	switch (ch) {
-	case '0':
-	case '1':
-	case '2':
-	case '3':
-	case '4':
-	case '5':
-	case '6':
-	case '7':
-	case '8':
-	case '9':
-	case 'a':
-	case 'A':
-	case 'b':
-	case 'B':
-	case 'c':
-	case 'C':
-	case 'd':
-	case 'D':
-	case 'e':
-	case 'E':
-	case 'f':
-	case 'F':
-		return (true);
-	default:
-		return (false);
-	}
-}
-
 int
 parse_enable(const char *enable)
 {
@@ -171,74 +140,6 @@ parse_enable(const char *enable)
 	return (ENABLE_UNSPECIFIED);
 }
 
-bool
-valid_iscsi_name(const char *name)
-{
-	int i;
-
-	if (strlen(name) >= MAX_NAME_LEN) {
-		xo_warnx("overlong name for \"%s\"; max length allowed "
-		    "by iSCSI specification is %d characters",
-		    name, MAX_NAME_LEN);
-		return (false);
-	}
-
-	/*
-	 * In the cases below, we don't return an error, just in case the admin
-	 * was right, and we're wrong.
-	 */
-	if (strncasecmp(name, "iqn.", strlen("iqn.")) == 0) {
-		for (i = strlen("iqn."); name[i] != '\0'; i++) {
-			/*
-			 * XXX: We should verify UTF-8 normalisation, as defined
-			 *      by 3.2.6.2: iSCSI Name Encoding.
-			 */
-			if (isalnum(name[i]))
-				continue;
-			if (name[i] == '-' || name[i] == '.' || name[i] == ':')
-				continue;
-			xo_warnx("invalid character \"%c\" in iSCSI name "
-			    "\"%s\"; allowed characters are letters, digits, "
-			    "'-', '.', and ':'", name[i], name);
-			break;
-		}
-		/*
-		 * XXX: Check more stuff: valid date and a valid reversed domain.
-		 */
-	} else if (strncasecmp(name, "eui.", strlen("eui.")) == 0) {
-		if (strlen(name) != strlen("eui.") + 16)
-			xo_warnx("invalid iSCSI name \"%s\"; the \"eui.\" "
-			    "should be followed by exactly 16 hexadecimal "
-			    "digits", name);
-		for (i = strlen("eui."); name[i] != '\0'; i++) {
-			if (!valid_hex(name[i])) {
-				xo_warnx("invalid character \"%c\" in iSCSI "
-				    "name \"%s\"; allowed characters are 1-9 "
-				    "and A-F", name[i], name);
-				break;
-			}
-		}
-	} else if (strncasecmp(name, "naa.", strlen("naa.")) == 0) {
-		if (strlen(name) > strlen("naa.") + 32)
-			xo_warnx("invalid iSCSI name \"%s\"; the \"naa.\" "
-			    "should be followed by at most 32 hexadecimal "
-			    "digits", name);
-		for (i = strlen("naa."); name[i] != '\0'; i++) {
-			if (!valid_hex(name[i])) {
-				xo_warnx("invalid character \"%c\" in ISCSI "
-				    "name \"%s\"; allowed characters are 1-9 "
-				    "and A-F", name[i], name);
-				break;
-			}
-		}
-	} else {
-		xo_warnx("invalid iSCSI name \"%s\"; should start with "
-		    "either \".iqn\", \"eui.\", or \"naa.\"",
-		    name);
-	}
-	return (true);
-}
-
 void
 conf_verify(struct conf *conf)
 {
@@ -257,7 +158,7 @@ conf_verify(struct conf *conf)
 			xo_errx(1, "cannot specify TargetName for discovery "
 			    "sessions for target \"%s\"", targ->t_nickname);
 		if (targ->t_name != NULL) {
-			if (valid_iscsi_name(targ->t_name) == false)
+			if (valid_iscsi_name(targ->t_name, xo_warnx) == false)
 				xo_errx(1, "invalid target name \"%s\"",
 				    targ->t_name);
 		}
@@ -268,7 +169,7 @@ conf_verify(struct conf *conf)
 			    targ->t_nickname);
 		if (targ->t_initiator_name == NULL)
 			targ->t_initiator_name = default_initiator_name();
-		if (valid_iscsi_name(targ->t_initiator_name) == false)
+		if (valid_iscsi_name(targ->t_initiator_name, xo_warnx) == false)
 			xo_errx(1, "invalid initiator name \"%s\"",
 			    targ->t_initiator_name);
 		if (targ->t_header_digest == DIGEST_UNSPECIFIED)
@@ -1014,7 +915,7 @@ main(int argc, char **argv)
 		    user, secret, enable);
 	} else {
 		if (Aflag != 0 && target != NULL) {
-			if (valid_iscsi_name(target) == false)
+			if (valid_iscsi_name(target, xo_warnx) == false)
 				xo_errx(1, "invalid target name \"%s\"", target);
 		}
 		conf = conf_new();
diff --git a/usr.bin/iscsictl/iscsictl.h b/usr.bin/iscsictl/iscsictl.h
index 3bc69e4877a9..dea1a6712dd8 100644
--- a/usr.bin/iscsictl/iscsictl.h
+++ b/usr.bin/iscsictl/iscsictl.h
@@ -40,8 +40,6 @@
 
 #define	ISCSICTL_XO_VERSION		"1"
 
-#define	MAX_NAME_LEN			223
-
 #define	AUTH_METHOD_UNSPECIFIED		0
 #define	AUTH_METHOD_NONE		1
 #define	AUTH_METHOD_CHAP		2
@@ -103,7 +101,6 @@ void		target_delete(struct target *ic);
 
 void		print_periphs(int session_id);
 
-bool		valid_iscsi_name(const char *name);
 int		parse_enable(const char *enable);
 
 #endif /* !ISCSICTL_H */
diff --git a/usr.sbin/ctld/ctld.c b/usr.sbin/ctld/ctld.c
index 3136a5d4b7cb..93a749b9109a 100644
--- a/usr.sbin/ctld/ctld.c
+++ b/usr.sbin/ctld/ctld.c
@@ -1072,106 +1072,6 @@ portal_group_set_redirection(struct portal_group *pg, const char *addr)
 	return (0);
 }
 
-static bool
-valid_hex(const char ch)
-{
-	switch (ch) {
-	case '0':
-	case '1':
-	case '2':
-	case '3':
-	case '4':
-	case '5':
-	case '6':
-	case '7':
-	case '8':
-	case '9':
-	case 'a':
-	case 'A':
-	case 'b':
-	case 'B':
-	case 'c':
-	case 'C':
-	case 'd':
-	case 'D':
-	case 'e':
-	case 'E':
-	case 'f':
-	case 'F':
-		return (true);
-	default:
-		return (false);
-	}
-}
-
-bool
-valid_iscsi_name(const char *name)
-{
-	int i;
-
-	if (strlen(name) >= MAX_NAME_LEN) {
-		log_warnx("overlong name for target \"%s\"; max length allowed "
-		    "by iSCSI specification is %d characters",
-		    name, MAX_NAME_LEN);
-		return (false);
-	}
-
-	/*
-	 * In the cases below, we don't return an error, just in case the admin
-	 * was right, and we're wrong.
-	 */
-	if (strncasecmp(name, "iqn.", strlen("iqn.")) == 0) {
-		for (i = strlen("iqn."); name[i] != '\0'; i++) {
-			/*
-			 * XXX: We should verify UTF-8 normalisation, as defined
-			 *      by 3.2.6.2: iSCSI Name Encoding.
-			 */
-			if (isalnum(name[i]))
-				continue;
-			if (name[i] == '-' || name[i] == '.' || name[i] == ':')
-				continue;
-			log_warnx("invalid character \"%c\" in target name "
-			    "\"%s\"; allowed characters are letters, digits, "
-			    "'-', '.', and ':'", name[i], name);
-			break;
-		}
-		/*
-		 * XXX: Check more stuff: valid date and a valid reversed domain.
-		 */
-	} else if (strncasecmp(name, "eui.", strlen("eui.")) == 0) {
-		if (strlen(name) != strlen("eui.") + 16)
-			log_warnx("invalid target name \"%s\"; the \"eui.\" "
-			    "should be followed by exactly 16 hexadecimal "
-			    "digits", name);
-		for (i = strlen("eui."); name[i] != '\0'; i++) {
-			if (!valid_hex(name[i])) {
-				log_warnx("invalid character \"%c\" in target "
-				    "name \"%s\"; allowed characters are 1-9 "
-				    "and A-F", name[i], name);
-				break;
-			}
-		}
-	} else if (strncasecmp(name, "naa.", strlen("naa.")) == 0) {
-		if (strlen(name) > strlen("naa.") + 32)
-			log_warnx("invalid target name \"%s\"; the \"naa.\" "
-			    "should be followed by at most 32 hexadecimal "
-			    "digits", name);
-		for (i = strlen("naa."); name[i] != '\0'; i++) {
-			if (!valid_hex(name[i])) {
-				log_warnx("invalid character \"%c\" in target "
-				    "name \"%s\"; allowed characters are 1-9 "
-				    "and A-F", name[i], name);
-				break;
-			}
-		}
-	} else {
-		log_warnx("invalid target name \"%s\"; should start with "
-		    "either \"iqn.\", \"eui.\", or \"naa.\"",
-		    name);
-	}
-	return (true);
-}
-
 struct pport *
 pport_new(struct kports *kports, const char *name, uint32_t ctl_port)
 {
@@ -1389,8 +1289,7 @@ target_new(struct conf *conf, const char *name)
 		log_warnx("duplicated target \"%s\"", name);
 		return (NULL);
 	}
-	if (valid_iscsi_name(name) == false) {
-		log_warnx("target name \"%s\" is invalid", name);
+	if (valid_iscsi_name(name, log_warnx) == false) {
 		return (NULL);
 	}
 	targ = calloc(1, sizeof(*targ));
diff --git a/usr.sbin/ctld/ctld.h b/usr.sbin/ctld/ctld.h
index 3f4b653d6896..88490a94464e 100644
--- a/usr.sbin/ctld/ctld.h
+++ b/usr.sbin/ctld/ctld.h
@@ -46,7 +46,6 @@
 #define	DEFAULT_CD_BLOCKSIZE		2048
 
 #define	MAX_LUNS			1024
-#define	MAX_NAME_LEN			223
 #define	MAX_DATA_SEGMENT_LENGTH		(128 * 1024)
 #define	SOCKBUF_SIZE			1048576
 
@@ -387,7 +386,6 @@ void			login(struct ctld_connection *conn);
 
 void			discovery(struct ctld_connection *conn);
 
-bool			valid_iscsi_name(const char *name);
 void			set_timeout(int timeout, int fatal);
 
 #endif /* !CTLD_H */
diff --git a/usr.sbin/ctld/login.c b/usr.sbin/ctld/login.c
index afd3210a828a..f57582f4e62f 100644
--- a/usr.sbin/ctld/login.c
+++ b/usr.sbin/ctld/login.c
@@ -874,7 +874,7 @@ login(struct ctld_connection *conn)
 		login_send_error(request, 0x02, 0x07);
 		log_errx(1, "received Login PDU without InitiatorName");
 	}
-	if (valid_iscsi_name(initiator_name) == false) {
+	if (valid_iscsi_name(initiator_name, log_warnx) == false) {
 		login_send_error(request, 0x02, 0x00);
 		log_errx(1, "received Login PDU with invalid InitiatorName");
 	}