git: 7f912714c536 - main - ctld: Convert struct auth to a C++ class
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Mon, 04 Aug 2025 19:46:42 UTC
The branch main has been updated by jhb:
URL: https://cgit.FreeBSD.org/src/commit/?id=7f912714c53644ea18fc58ffa364918ccfa22999
commit 7f912714c53644ea18fc58ffa364918ccfa22999
Author: John Baldwin <jhb@FreeBSD.org>
AuthorDate: 2025-08-04 19:38:06 +0000
Commit: John Baldwin <jhb@FreeBSD.org>
CommitDate: 2025-08-04 19:38:06 +0000
ctld: Convert struct auth to a C++ class
Use private std::string to hold secret and mutual authentication strings
along with accessors to retrieve constant C versions of those strings.
Add a helper function to determine if an auth object contains mutual
credentials.
Instead of storing the user name in the structure, use an
unordered_map<> with the username as the key for the ag_auths member
of auth_group. Add a parse error if multiple credentials specify the
same user. Previously the code always used the first credential when
verifying and ignored additional credentials silently.
Sponsored by: Chelsio Communications
Pull Request: https://github.com/freebsd/freebsd-src/pull/1794
---
usr.sbin/ctld/ctld.cc | 72 +++++++++++++---------------------------------
usr.sbin/ctld/ctld.hh | 28 +++++++++++++-----
usr.sbin/ctld/discovery.cc | 2 +-
usr.sbin/ctld/login.cc | 31 ++++++++++----------
4 files changed, 57 insertions(+), 76 deletions(-)
diff --git a/usr.sbin/ctld/ctld.cc b/usr.sbin/ctld/ctld.cc
index ba65befa2d0a..558ddb8ac6aa 100644
--- a/usr.sbin/ctld/ctld.cc
+++ b/usr.sbin/ctld/ctld.cc
@@ -143,42 +143,14 @@ conf_delete(struct conf *conf)
free(conf);
}
-static struct auth *
-auth_new(struct auth_group *ag)
-{
- struct auth *auth;
-
- auth = reinterpret_cast<struct auth *>(calloc(1, sizeof(*auth)));
- if (auth == NULL)
- log_err(1, "calloc");
- auth->a_auth_group = ag;
- TAILQ_INSERT_TAIL(&ag->ag_auths, auth, a_next);
- return (auth);
-}
-
-static void
-auth_delete(struct auth *auth)
-{
- TAILQ_REMOVE(&auth->a_auth_group->ag_auths, auth, a_next);
-
- free(auth->a_user);
- free(auth->a_secret);
- free(auth->a_mutual_user);
- free(auth->a_mutual_secret);
- free(auth);
-}
-
const struct auth *
auth_find(const struct auth_group *ag, const char *user)
{
- const struct auth *auth;
+ auto it = ag->ag_auths.find(user);
+ if (it == ag->ag_auths.end())
+ return (nullptr);
- TAILQ_FOREACH(auth, &ag->ag_auths, a_next) {
- if (strcmp(auth->a_user, user) == 0)
- return (auth);
- }
-
- return (NULL);
+ return (&it->second);
}
static void
@@ -188,6 +160,7 @@ auth_check_secret_length(const struct auth_group *ag, const char *user,
size_t len;
len = strlen(secret);
+ assert(len != 0);
if (len > 16) {
log_warnx("%s for user \"%s\", %s, is too long; it should be "
"at most 16 characters long", secret_type, user,
@@ -204,8 +177,6 @@ bool
auth_new_chap(struct auth_group *ag, const char *user,
const char *secret)
{
- struct auth *auth;
-
if (ag->ag_type == AG_TYPE_UNKNOWN)
ag->ag_type = AG_TYPE_CHAP;
if (ag->ag_type != AG_TYPE_CHAP) {
@@ -216,9 +187,12 @@ auth_new_chap(struct auth_group *ag, const char *user,
auth_check_secret_length(ag, user, secret, "secret");
- auth = auth_new(ag);
- auth->a_user = checked_strdup(user);
- auth->a_secret = checked_strdup(secret);
+ const auto &pair = ag->ag_auths.try_emplace(user, secret);
+ if (!pair.second) {
+ log_warnx("duplicate credentials for user \"%s\" for %s",
+ user, ag->ag_label);
+ return (false);
+ }
return (true);
}
@@ -227,8 +201,6 @@ bool
auth_new_chap_mutual(struct auth_group *ag, const char *user,
const char *secret, const char *user2, const char *secret2)
{
- struct auth *auth;
-
if (ag->ag_type == AG_TYPE_UNKNOWN)
ag->ag_type = AG_TYPE_CHAP_MUTUAL;
if (ag->ag_type != AG_TYPE_CHAP_MUTUAL) {
@@ -240,11 +212,13 @@ auth_new_chap_mutual(struct auth_group *ag, const char *user,
auth_check_secret_length(ag, user, secret, "secret");
auth_check_secret_length(ag, user, secret2, "mutual secret");
- auth = auth_new(ag);
- auth->a_user = checked_strdup(user);
- auth->a_secret = checked_strdup(secret);
- auth->a_mutual_user = checked_strdup(user2);
- auth->a_mutual_secret = checked_strdup(secret2);
+ const auto &pair = ag->ag_auths.try_emplace(user, secret, user2,
+ secret2);
+ if (!pair.second) {
+ log_warnx("duplicate credentials for user \"%s\" for %s",
+ user, ag->ag_label);
+ return (false);
+ }
return (true);
}
@@ -442,13 +416,10 @@ auth_group_create(struct conf *conf, const char *name, char *label)
{
struct auth_group *ag;
- ag = reinterpret_cast<struct auth_group *>(calloc(1, sizeof(*ag)));
- if (ag == NULL)
- log_err(1, "calloc");
+ ag = new auth_group();
if (name != NULL)
ag->ag_name = checked_strdup(name);
ag->ag_label = label;
- TAILQ_INIT(&ag->ag_auths);
TAILQ_INIT(&ag->ag_names);
TAILQ_INIT(&ag->ag_portals);
ag->ag_conf = conf;
@@ -485,14 +456,11 @@ auth_group_new(struct conf *conf, struct target *target)
void
auth_group_delete(struct auth_group *ag)
{
- struct auth *auth, *auth_tmp;
struct auth_name *auth_name, *auth_name_tmp;
struct auth_portal *auth_portal, *auth_portal_tmp;
TAILQ_REMOVE(&ag->ag_conf->conf_auth_groups, ag, ag_next);
- TAILQ_FOREACH_SAFE(auth, &ag->ag_auths, a_next, auth_tmp)
- auth_delete(auth);
TAILQ_FOREACH_SAFE(auth_name, &ag->ag_names, an_next, auth_name_tmp)
auth_name_delete(auth_name);
TAILQ_FOREACH_SAFE(auth_portal, &ag->ag_portals, ap_next,
@@ -500,7 +468,7 @@ auth_group_delete(struct auth_group *ag)
auth_portal_delete(auth_portal);
free(ag->ag_label);
free(ag->ag_name);
- free(ag);
+ delete ag;
}
struct auth_group *
diff --git a/usr.sbin/ctld/ctld.hh b/usr.sbin/ctld/ctld.hh
index 61e453d8dc23..a2cedeaf77da 100644
--- a/usr.sbin/ctld/ctld.hh
+++ b/usr.sbin/ctld/ctld.hh
@@ -41,6 +41,10 @@
#include <libiscsiutil.h>
#include <libutil.h>
+#include <string>
+#include <string_view>
+#include <unordered_map>
+
#define DEFAULT_CONFIG_PATH "/etc/ctl.conf"
#define DEFAULT_PIDFILE "/var/run/ctld.pid"
#define DEFAULT_BLOCKSIZE 512
@@ -50,12 +54,22 @@
#define SOCKBUF_SIZE 1048576
struct auth {
- TAILQ_ENTRY(auth) a_next;
- struct auth_group *a_auth_group;
- char *a_user;
- char *a_secret;
- char *a_mutual_user;
- char *a_mutual_secret;
+ auth(std::string_view secret) : a_secret(secret) {}
+ auth(std::string_view secret, std::string_view mutual_user,
+ std::string_view mutual_secret) :
+ a_secret(secret), a_mutual_user(mutual_user),
+ a_mutual_secret(mutual_secret) {}
+
+ bool mutual() const { return !a_mutual_user.empty(); }
+
+ const char *secret() const { return a_secret.c_str(); }
+ const char *mutual_user() const { return a_mutual_user.c_str(); }
+ const char *mutual_secret() const { return a_mutual_secret.c_str(); }
+
+private:
+ std::string a_secret;
+ std::string a_mutual_user;
+ std::string a_mutual_secret;
};
struct auth_name {
@@ -84,7 +98,7 @@ struct auth_group {
char *ag_name;
char *ag_label;
int ag_type;
- TAILQ_HEAD(, auth) ag_auths;
+ std::unordered_map<std::string, auth> ag_auths;
TAILQ_HEAD(, auth_name) ag_names;
TAILQ_HEAD(, auth_portal) ag_portals;
};
diff --git a/usr.sbin/ctld/discovery.cc b/usr.sbin/ctld/discovery.cc
index 3cf1b94a9619..c4bfb94669f9 100644
--- a/usr.sbin/ctld/discovery.cc
+++ b/usr.sbin/ctld/discovery.cc
@@ -196,7 +196,7 @@ discovery_target_filtered_out(const struct ctld_connection *conn,
return (true);
}
- error = chap_authenticate(conn->conn_chap, auth->a_secret);
+ error = chap_authenticate(conn->conn_chap, auth->secret());
if (error != 0) {
log_debugx("password for CHAP user \"%s\" doesn't "
"match target \"%s\"; skipping",
diff --git a/usr.sbin/ctld/login.cc b/usr.sbin/ctld/login.cc
index e891a3ed4b67..549fa0c397ad 100644
--- a/usr.sbin/ctld/login.cc
+++ b/usr.sbin/ctld/login.cc
@@ -336,7 +336,7 @@ login_send_chap_c(struct pdu *request, struct chap *chap)
static struct pdu *
login_receive_chap_r(struct connection *conn, struct auth_group *ag,
- struct chap *chap, const struct auth **authp)
+ struct chap *chap, const struct auth **authp, std::string &user)
{
struct pdu *request;
struct keys *request_keys;
@@ -376,15 +376,13 @@ login_receive_chap_r(struct connection *conn, struct auth_group *ag,
chap_n);
}
- assert(auth->a_secret != NULL);
- assert(strlen(auth->a_secret) > 0);
-
- error = chap_authenticate(chap, auth->a_secret);
+ error = chap_authenticate(chap, auth->secret());
if (error != 0) {
login_send_error(request, 0x02, 0x01);
log_errx(1, "CHAP authentication failed for user \"%s\"",
- auth->a_user);
+ chap_n);
}
+ user = chap_n;
keys_delete(request_keys);
@@ -394,7 +392,7 @@ login_receive_chap_r(struct connection *conn, struct auth_group *ag,
static void
login_send_chap_success(struct pdu *request,
- const struct auth *auth)
+ const struct auth *auth, const std::string &user)
{
struct pdu *response;
struct keys *request_keys, *response_keys;
@@ -424,17 +422,17 @@ login_send_chap_success(struct pdu *request,
log_errx(1, "initiator requested target "
"authentication, but didn't send CHAP_C");
}
- if (auth->a_auth_group->ag_type != AG_TYPE_CHAP_MUTUAL) {
+ if (!auth->mutual()) {
login_send_error(request, 0x02, 0x01);
log_errx(1, "initiator requests target authentication "
"for user \"%s\", but mutual user/secret "
- "is not set", auth->a_user);
+ "is not set", user.c_str());
}
log_debugx("performing mutual authentication as user \"%s\"",
- auth->a_mutual_user);
+ auth->mutual_user());
- rchap = rchap_new(auth->a_mutual_secret);
+ rchap = rchap_new(auth->mutual_secret());
error = rchap_receive(rchap, chap_i, chap_c);
if (error != 0) {
login_send_error(request, 0x02, 0x07);
@@ -444,7 +442,7 @@ login_send_chap_success(struct pdu *request,
chap_r = rchap_get_response(rchap);
rchap_delete(rchap);
response_keys = keys_new();
- keys_add(response_keys, "CHAP_N", auth->a_mutual_user);
+ keys_add(response_keys, "CHAP_N", auth->mutual_user());
keys_add(response_keys, "CHAP_R", chap_r);
free(chap_r);
keys_save_pdu(response_keys, response);
@@ -461,6 +459,7 @@ login_send_chap_success(struct pdu *request,
static void
login_chap(struct ctld_connection *conn, struct auth_group *ag)
{
+ std::string user;
const struct auth *auth;
struct chap *chap;
struct pdu *request;
@@ -488,20 +487,20 @@ login_chap(struct ctld_connection *conn, struct auth_group *ag)
* Receive CHAP_N/CHAP_R PDU and authenticate.
*/
log_debugx("waiting for CHAP_N/CHAP_R");
- request = login_receive_chap_r(&conn->conn, ag, chap, &auth);
+ request = login_receive_chap_r(&conn->conn, ag, chap, &auth, user);
/*
* Yay, authentication succeeded!
*/
log_debugx("authentication succeeded for user \"%s\"; "
- "transitioning to operational parameter negotiation", auth->a_user);
- login_send_chap_success(request, auth);
+ "transitioning to operational parameter negotiation", user.c_str());
+ login_send_chap_success(request, auth, user);
pdu_delete(request);
/*
* Leave username and CHAP information for discovery().
*/
- conn->conn_user = auth->a_user;
+ conn->conn_user = checked_strdup(user.c_str());
conn->conn_chap = chap;
}