From 082452bfb5a428d53df92ce407afe72e073527b0 Mon Sep 17 00:00:00 2001 From: Vivek Kumar Dutta Date: Tue, 29 Jul 2025 17:54:54 +0530 Subject: [PATCH] mosquitto-auth-shadow: support libpam based authentication --- mosquitto-auth-shadow/Config.in | 7 ++ mosquitto-auth-shadow/Makefile | 13 ++- mosquitto-auth-shadow/src/Makefile | 2 +- .../src/mosquitto_auth_shadow.c | 84 +++++++++++++++++-- 4 files changed, 97 insertions(+), 9 deletions(-) create mode 100644 mosquitto-auth-shadow/Config.in diff --git a/mosquitto-auth-shadow/Config.in b/mosquitto-auth-shadow/Config.in new file mode 100644 index 000000000..c82ff37af --- /dev/null +++ b/mosquitto-auth-shadow/Config.in @@ -0,0 +1,7 @@ +if PACKAGE_mosquitto-auth-shadow + +config MOSQUITTO_AUTH_PAM_SUPPORT + bool "Enable support of Linux PAM module for Authentication" + default y + +endif diff --git a/mosquitto-auth-shadow/Makefile b/mosquitto-auth-shadow/Makefile index 5c0dead78..98d1c95a2 100644 --- a/mosquitto-auth-shadow/Makefile +++ b/mosquitto-auth-shadow/Makefile @@ -14,12 +14,13 @@ include $(TOPDIR)/rules.mk PKG_NAME:=mosquitto-auth-shadow -PKG_VERSION:=1.0.1 +PKG_VERSION:=1.1.0 PKG_MAINTAINER:=Erik Karlsson PKG_LICENSE:=EPL-2.0 PKG_BUILD_PARALLEL:=1 +PKG_CONFIG_DEPENDS:=CONFIG_MOSQUITTO_AUTH_PAM_SUPPORT include $(INCLUDE_DIR)/package.mk @@ -27,7 +28,7 @@ define Package/mosquitto-auth-shadow SECTION:=net CATEGORY:=Network TITLE:=mosquitto - /etc/shadow authentication plugin - DEPENDS:=+mosquitto-ssl + DEPENDS:=+mosquitto-ssl +MOSQUITTO_AUTH_PAM_SUPPORT:libpam USERID:=mosquitto=200:mosquitto=200 mosquitto=200:shadow=11 endef @@ -36,6 +37,14 @@ define Package/mosquitto-auth-shadow/description users using /etc/shadow endef +define Package/mosquitto-auth-shadow/config + source "$(SOURCE)/Config.in" +endef + +ifeq ($(CONFIG_MOSQUITTO_AUTH_PAM_SUPPORT),y) +TARGET_CFLAGS+=-DENABLE_PAM_SUPPORT +endif + define Package/mosquitto-auth-shadow/install $(INSTALL_DIR) $(1)/usr/lib $(INSTALL_BIN) $(PKG_BUILD_DIR)/mosquitto_auth_shadow.so $(1)/usr/lib/ diff --git a/mosquitto-auth-shadow/src/Makefile b/mosquitto-auth-shadow/src/Makefile index 63378032c..3e5e20ab3 100644 --- a/mosquitto-auth-shadow/src/Makefile +++ b/mosquitto-auth-shadow/src/Makefile @@ -19,7 +19,7 @@ all: $(TARGETS) $(CC) $(CFLAGS) -Wall -Werror -fPIC -c -o $@ $< mosquitto_auth_shadow.so: mosquitto_auth_shadow.pic.o - $(CC) $(LDFLAGS) -shared -o $@ $^ + $(CC) $(LDFLAGS) -shared -o $@ $^ $(if $(filter -DENABLE_PAM_SUPPORT,$(CFLAGS)),-lpam) clean: rm -f *.o $(TARGETS) diff --git a/mosquitto-auth-shadow/src/mosquitto_auth_shadow.c b/mosquitto-auth-shadow/src/mosquitto_auth_shadow.c index 89bd1e0cb..9d72565d9 100644 --- a/mosquitto-auth-shadow/src/mosquitto_auth_shadow.c +++ b/mosquitto-auth-shadow/src/mosquitto_auth_shadow.c @@ -15,22 +15,78 @@ #include #include #include +#include #include #include #include -static int basic_auth_callback(int event, void *event_data, void *userdata) +#ifdef ENABLE_PAM_SUPPORT +#include + +static int pam_conversation(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr) +{ + int i; + const char *pass = (const char *)appdata_ptr; + + *resp = calloc(num_msg, sizeof(struct pam_response)); + if (*resp == NULL) { + mosquitto_log_printf(MOSQ_LOG_ERR, "pam failed to allocate buffer for validation"); + return PAM_BUF_ERR; + } + + if (pass == NULL) + return PAM_SUCCESS; + + for (i = 0; i < num_msg; ++i) { + if (msg[i]->msg_style == PAM_PROMPT_ECHO_OFF) { + (*resp)[i].resp = strdup(pass); + if ((*resp)[i].resp == NULL) { + for (int j = 0; j < i ; j++) + free((*resp)[j].resp); + + free(*resp); + *resp = NULL; + mosquitto_log_printf(MOSQ_LOG_ERR, "pam failed in strdup"); + return PAM_BUF_ERR; + } + } + } + return PAM_SUCCESS; +} + +static int process_pam_auth_callback(struct mosquitto_evt_basic_auth *ed) +{ + struct pam_conv conv; + int retval; + pam_handle_t *pamh = NULL; + + conv.conv = pam_conversation; + conv.appdata_ptr = (void *)ed->password; + + retval = pam_start("mosquitto", ed->username, &conv, &pamh); + if (retval != PAM_SUCCESS) { + mosquitto_log_printf(MOSQ_LOG_ERR, "pam start failed: %s", pam_strerror(pamh, retval)); + return MOSQ_ERR_AUTH; + } + + retval = pam_authenticate(pamh, 0); + pam_end(pamh, retval); + if (retval == PAM_SUCCESS) { + mosquitto_log_printf(MOSQ_LOG_NOTICE, "pam user [%s] logged in", ed->username); + return MOSQ_ERR_SUCCESS; + } + + mosquitto_log_printf(MOSQ_LOG_NOTICE, "pam user [%s] failed authentication, err [%s]", ed->username, pam_strerror(pamh, retval)); + return MOSQ_ERR_AUTH; +} +#else +static int process_shadow_auth_callback(struct mosquitto_evt_basic_auth *ed) { - struct mosquitto_evt_basic_auth *ed = event_data; struct spwd spbuf, *sp = NULL; char buf[256]; struct crypt_data data; char *hash; - /* Let other plugins or broker decide about anonymous login */ - if (ed->username == NULL) - return MOSQ_ERR_PLUGIN_DEFER; - getspnam_r(ed->username, &spbuf, buf, sizeof(buf), &sp); if (sp == NULL || sp->sp_pwdp == NULL) @@ -54,6 +110,22 @@ static int basic_auth_callback(int event, void *event_data, void *userdata) return MOSQ_ERR_AUTH; } +#endif + +static int basic_auth_callback(int event, void *event_data, void *userdata) +{ + struct mosquitto_evt_basic_auth *ed = event_data; + + /* Let other plugins or broker decide about anonymous login */ + if (ed->username == NULL) + return MOSQ_ERR_PLUGIN_DEFER; + +#ifdef ENABLE_PAM_SUPPORT + return process_pam_auth_callback(ed); +#else + return process_shadow_auth_callback(ed); +#endif +} int mosquitto_plugin_version(int supported_version_count, const int *supported_versions)