From f8b3ccaa4edd4836885dc3e22062b69e80883f36 Mon Sep 17 00:00:00 2001
From: Loïc Collignon <loic.collignon@iot.bzh>
Date: Thu, 26 Oct 2017 16:27:49 +0200
Subject: add nfc pam module
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Change-Id: Icc42361f64948e2c2ab082fa973793f19737df2d
Signed-off-by: Loïc Collignon <loic.collignon@iot.bzh>
---
 pam_agl/CMakeLists.txt |  27 +++---
 pam_agl/pam_agl.c      | 223 -------------------------------------------------
 pam_agl/pam_agl_nfc.c  | 152 +++++++++++++++++++++++++++++++++
 pam_agl/pam_agl_usb.c  | 186 +++++++++++++++++++++++++++++++++++++++++
 4 files changed, 355 insertions(+), 233 deletions(-)
 delete mode 100644 pam_agl/pam_agl.c
 create mode 100644 pam_agl/pam_agl_nfc.c
 create mode 100644 pam_agl/pam_agl_usb.c

diff --git a/pam_agl/CMakeLists.txt b/pam_agl/CMakeLists.txt
index 17c85be..7cd39cc 100644
--- a/pam_agl/CMakeLists.txt
+++ b/pam_agl/CMakeLists.txt
@@ -25,22 +25,29 @@ include(FindPkgConfig)
 set(PAM_INCLUDE_DIR "/usr/include/")
 set(PAM_LIBRARY "/lib64/libpam.so.0")
 include_directories(${PAM_INCLUDE_DIR})
+if (NOT DEFINED CMAKE_INSTALL_LIBDIR)
+	get_filename_component(CMAKE_INSTALL_LIBDIR ${PAM_LIBRARY} DIRECTORY)
+endif()
 
 # Find json-c
 pkg_check_modules(${JSON_C} REQUIRED json-c)
 include_directories(${${JSON_C}_INCLUDE_DIRS})
 add_compile_options(${${JSON_C}_CFLAGS})
 
-# Add the target
-add_library(pam_agl SHARED pam_agl.c)
-target_link_libraries(pam_agl ${PAM_LIBRARY} ${${JSON_C}_LIBRARIES})
-#list (APPEND link_libraries ${${JSON_C}_LDFLAGS})
-set_property(TARGET pam_agl PROPERTY POSITION_INDEPENDENT_CODE ON)
-set_property(TARGET pam_agl PROPERTY PREFIX "")
+# Add the pam_agl_usb target
+add_library(pam_agl_usb SHARED pam_agl_usb.c)
+target_link_libraries(pam_agl_usb ${PAM_LIBRARY} ${${JSON_C}_LIBRARIES})
+set_property(TARGET pam_agl_usb PROPERTY POSITION_INDEPENDENT_CODE ON)
+set_property(TARGET pam_agl_usb PROPERTY PREFIX "")
 
-if (NOT DEFINED CMAKE_INSTALL_LIBDIR)
-	get_filename_component(CMAKE_INSTALL_LIBDIR ${PAM_LIBRARY} DIRECTORY)
-endif()
+install(TARGETS pam_agl_usb
+	LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}/security/")
+	
+# Add the pam_agl_nfc target
+add_library(pam_agl_nfc SHARED pam_agl_nfc.c)
+target_link_libraries(pam_agl_nfc ${PAM_LIBRARY} ${${JSON_C}_LIBRARIES})
+set_property(TARGET pam_agl_nfc PROPERTY POSITION_INDEPENDENT_CODE ON)
+set_property(TARGET pam_agl_nfc PROPERTY PREFIX "")
 
-install(TARGETS pam_agl
+install(TARGETS pam_agl_nfc
 	LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}/security/")
diff --git a/pam_agl/pam_agl.c b/pam_agl/pam_agl.c
deleted file mode 100644
index c85979d..0000000
--- a/pam_agl/pam_agl.c
+++ /dev/null
@@ -1,223 +0,0 @@
-#include <fcntl.h>
-#include <stdarg.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <uuid/uuid.h>
-#include <json-c/json.h>
-
-#define PAM_SM_AUTH
-#define PAM_SM_ACCOUNT
-#define PAM_SM_SESSION
-#define PAM_SM_PASSWORD
-#include <security/pam_modules.h>
-#include <security/pam_appl.h>
-
-#define DATABASE_FILE "/etc/agl/keys.json"
-
-#define BLOCK_SIZE 4096
-typedef struct header_
-{
-	char mn[4];
-	size_t size;
-} header;
-
-int is_valid_mn(const char* v)
-{
-	return v && v[0] == 'I' && v[1] == 'D' && v[2] == 'K' && v[3] == 'Y';
-}
-
-char* get_file_content(const char* path)
-{
-	char* buffer;
-	long length;
-	FILE* f;
-	
-	buffer = NULL;
-	length = 0;
-	
-	f = fopen(path, "rb");
-	if (f)
-	{
-		fseek(f, 0, SEEK_END);
-		length = ftell(f);
-		fseek(f, 0, SEEK_SET);
-		buffer = malloc(length + 1);
-		if (buffer)
-		{
-			if (fread (buffer, 1, length, f) != length)
-			{
-				free(buffer);
-				buffer = NULL;
-			}
-			else buffer[length] = 0;
-		}
-		fclose (f);
-	}
-	
-	return buffer;
-}
-
-int read_device(const char* device, char** idkey)
-{
-	int fd;
-	ssize_t sz;
-	header h;
-		
-	printf("[PAM DEBUG] check_device %s...\n", device);
-	fd = open(device, O_RDONLY);
-	if (fd == -1)
-	{
-		printf("[PAM DEBUG] Failed to open the device %s!\n", device);
-		return PAM_SERVICE_ERR;
-	}
-
-	sz = read(fd, &h, sizeof(header));
-	if (sz != sizeof(header) || !is_valid_mn(h.mn) || h.size < 1) { close(fd); printf("[PAM DEBUG]: bad header!\n"); return PAM_SERVICE_ERR; }
-	printf("[PAM DEBUG]: data size=%lu\n", h.size);
-
-	*idkey = (char*)malloc(h.size + 1);
-	if (!*idkey) { close(fd); printf("[PAM DEBUG] Bad alloc!\n"); return PAM_SERVICE_ERR; }
-
-	memset(*idkey, 0, h.size + 1);
-	sz = read(fd, *idkey, h.size);
-	close(fd);
-	if (sz != h.size) { free(idkey); printf("[PAM DEBUG] Bad data read!\n"); return PAM_SERVICE_ERR; }
-	return PAM_SUCCESS;
-}
-
-int authenticate(pam_handle_t* pamh, const char* uuid)
-{
-	char* file_content;
-	struct json_object* database;
-	struct json_object* key;
-
-	file_content = get_file_content(DATABASE_FILE);
-	if (!file_content)
-	{
-		printf("[PAM DEBUG] Failed to read database file (%s)\n", DATABASE_FILE);
-		return PAM_SERVICE_ERR;
-	}
-	
-	database = json_tokener_parse(file_content);
-	if (!database)
-	{
-		printf("[PAM DEBUG] Failed to parse the database\n");
-		return PAM_SERVICE_ERR;
-	}
-	
-	if (json_object_object_get_ex(database, uuid, &key))
-	{
-		printf("[PAM] Key found!\n");
-		printf("[PAM DEBUG] pam_set_item(\"%s\")\n", uuid);
-		pam_set_item(pamh, PAM_USER, uuid);
-			
-		const char* pam_authtok;
-		if (pam_get_item(pamh, PAM_AUTHTOK, (const void**)&pam_authtok) == PAM_SUCCESS && !pam_authtok)
-			pam_set_item(pamh, PAM_AUTHTOK, uuid);
-		
-		json_object_put(database);
-		free(file_content);
-		return PAM_SUCCESS;
-	}
-	
-	printf("[PAM] Key not found!\n");
-	free(file_content);
-	if (database) json_object_put(database);
-	return PAM_AUTH_ERR;
-}
-
-int check_device(pam_handle_t* pamh, const char* device)
-{
-	char* idkey;
-	int ret;
-	
-	ret = read_device(device, &idkey);
-	if (ret != PAM_SUCCESS) return ret;
-	
-	printf("[PAM DEBUG] Data read:\n%s\n", idkey);
-	
-	json_object* idkey_json = json_tokener_parse(idkey);
-	if (!idkey_json)
-	{
-		free(idkey);
-		printf("[PAM DEBUG] Failed to parse json data!\n");
-		return PAM_SERVICE_ERR;
-	}
-
-	json_object* uuid_json;
-	if(!json_object_object_get_ex(idkey_json, "uuid", &uuid_json))
-	{
-		free(idkey);
-		printf("[PAM DEBUG] The json does not contains a valid uuid\n");
-		return PAM_SERVICE_ERR;
-	}
-
-	const char* uuid = json_object_get_string(uuid_json);
-	printf("[PAM DEBUG] uuid: %s\n", uuid);
-	
-	ret = authenticate(pamh, uuid);
-	free(idkey);
-	json_object_put(idkey_json);
-	return ret;
-}
-
-void log_pam(const char* fname, int flags, int argc, const char** argv, const char* device)
-{
-	printf("[PAM DEBUG] ---------- %s ----------\n", fname);
-	printf("[PAM DEBUG] flags: %d\n", flags);
-	for(int i = 0; i < argc; ++i)
-	{
-		printf("[PAM DEBUG] argv[%d]: %s\n", i, argv[i]);
-	}
-	printf("[PAM DEBUG] device: %s\n", device);
-	printf("[PAM DEBUG] ----------------------------------------\n");
-}
-
-/*!
-	@brief The pam_sm_authenticate function is the service module's implementation
-	of the pam_authenticate(3) interface.
-	This function performs the task of authenticating the user.
-
-	@param[in] pamh Unknown.
-	@param[in] flags PAM_SILENT and/or PAM_DISALLOW_NULL_AUTHTOK.
-	@return PAM_SUCCESS if ok.
-*/
-PAM_EXTERN int pam_sm_authenticate(pam_handle_t* pamh, int flags, int argc, const char** argv)
-{
-	const char* device = pam_getenv(pamh, "DEVICE");
-	log_pam("pam_sm_authenticate", flags, argc, argv, device);
-	return check_device(pamh, device);
-}
-
-PAM_EXTERN int pam_sm_setcred(pam_handle_t* pamh, int flags, int argc, const char** argv)
-{
-	log_pam("pam_sm_setcred", flags, argc, argv, pam_getenv(pamh, "DEVICE"));
-	return PAM_SUCCESS;
-}
-
-PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t* pamh, int flags, int argc, const char** argv)
-{
-	log_pam("pam_sm_acct_mgmt", flags, argc, argv, pam_getenv(pamh, "DEVICE"));
-	return PAM_SUCCESS;
-}
-
-PAM_EXTERN int pam_sm_open_session(pam_handle_t* pamh, int flags, int argc, const char** argv)
-{
-	log_pam("pam_sm_open_session", flags, argc, argv, pam_getenv(pamh, "DEVICE"));
-	return PAM_SUCCESS;
-}
-
-PAM_EXTERN int pam_sm_close_session(pam_handle_t* pamh, int flags, int argc, const char** argv)
-{
-	log_pam("pam_sm_close_session", flags, argc, argv, pam_getenv(pamh, "DEVICE"));
-	return PAM_SUCCESS;
-}
-
-PAM_EXTERN int pam_sm_chauthtok(pam_handle_t* pamh, int flags, int argc, const char** argv)
-{
-	log_pam("pam_sm_chauthtok", flags, argc, argv, pam_getenv(pamh, "DEVICE"));
-	return PAM_SUCCESS;
-}
diff --git a/pam_agl/pam_agl_nfc.c b/pam_agl/pam_agl_nfc.c
new file mode 100644
index 0000000..b25ba5c
--- /dev/null
+++ b/pam_agl/pam_agl_nfc.c
@@ -0,0 +1,152 @@
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <uuid/uuid.h>
+#include <json-c/json.h>
+
+#define PAM_SM_AUTH
+#define PAM_SM_ACCOUNT
+#define PAM_SM_SESSION
+#define PAM_SM_PASSWORD
+#include <security/pam_modules.h>
+#include <security/pam_appl.h>
+
+#include <security/pam_client.h>
+#include <security/pam_ext.h>
+#include <security/pam_filter.h>
+#include <security/pam_misc.h>
+#include <security/pam_modutil.h>
+
+#define DATABASE_FILE "/etc/agl/keys.json"
+
+int authenticate(pam_handle_t* pamh, const char* uid)
+{
+	struct json_object* database;
+	struct json_object* nfc;
+	struct json_object* key;
+
+	database = json_object_from_file(DATABASE_FILE);
+	if (!database)
+	{
+		printf("[PAM DEBUG] Failed to parse the database\n");
+		return PAM_SERVICE_ERR;
+	}
+	
+	if (json_object_object_get_ex(database, "nfc", &nfc))
+	{	
+		if (json_object_object_get_ex(nfc, uid, &key))
+		{
+			printf("[PAM] Key found!\n");
+			printf("[PAM DEBUG] pam_set_item(\"%s\")\n", uid);
+			pam_set_item(pamh, PAM_USER, uid);
+				
+			const char* pam_authtok;
+			if (pam_get_item(pamh, PAM_AUTHTOK, (const void**)&pam_authtok) == PAM_SUCCESS && !pam_authtok)
+				pam_set_item(pamh, PAM_AUTHTOK, uid);
+			
+			json_object_put(database);
+			return PAM_SUCCESS;
+		}
+	}
+	
+	printf("[PAM] Key not found!\n");
+	if (database) json_object_put(database);
+	return PAM_AUTH_ERR;
+}
+
+int check_device(pam_handle_t* pamh, const char* device)
+{
+	char* idkey;
+	int ret;
+	
+	ret = read_device(device, &idkey);
+	if (ret != PAM_SUCCESS) return ret;
+	
+	printf("[PAM DEBUG] Data read:\n%s\n", idkey);
+	
+	json_object* idkey_json = json_tokener_parse(idkey);
+	if (!idkey_json)
+	{
+		free(idkey);
+		printf("[PAM DEBUG] Failed to parse json data!\n");
+		return PAM_SERVICE_ERR;
+	}
+
+	json_object* uuid_json;
+	if(!json_object_object_get_ex(idkey_json, "uuid", &uuid_json))
+	{
+		free(idkey);
+		printf("[PAM DEBUG] The json does not contains a valid uuid\n");
+		return PAM_SERVICE_ERR;
+	}
+
+	const char* uuid = json_object_get_string(uuid_json);
+	printf("[PAM DEBUG] uuid: %s\n", uuid);
+	
+	ret = authenticate(pamh, uuid);
+	free(idkey);
+	json_object_put(idkey_json);
+	return ret;
+}
+
+void log_pam(const char* fname, int flags, int argc, const char** argv, const char* device)
+{
+	printf("[PAM DEBUG] ---------- %s ----------\n", fname);
+	printf("[PAM DEBUG] flags: %d\n", flags);
+	for(int i = 0; i < argc; ++i)
+	{
+		printf("[PAM DEBUG] argv[%d]: %s\n", i, argv[i]);
+	}
+	printf("[PAM DEBUG] device: %s\n", device);
+	printf("[PAM DEBUG] ----------------------------------------\n");
+}
+
+/*!
+	@brief The pam_sm_authenticate function is the service module's implementation
+	of the pam_authenticate(3) interface.
+	This function performs the task of authenticating the user.
+
+	@param[in] pamh Unknown.
+	@param[in] flags PAM_SILENT and/or PAM_DISALLOW_NULL_AUTHTOK.
+	@return PAM_SUCCESS if ok.
+*/
+PAM_EXTERN int pam_sm_authenticate(pam_handle_t* pamh, int flags, int argc, const char** argv)
+{
+	const char* uid = pam_getenv(pamh, "UID");
+	log_pam("pam_sm_authenticate", flags, argc, argv, uid);
+	return authenticate(pamh, uid);
+}
+
+PAM_EXTERN int pam_sm_setcred(pam_handle_t* pamh, int flags, int argc, const char** argv)
+{
+	log_pam("pam_sm_setcred", flags, argc, argv, pam_getenv(pamh, "DEVICE"));
+	return PAM_SUCCESS;
+}
+
+PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t* pamh, int flags, int argc, const char** argv)
+{
+	log_pam("pam_sm_acct_mgmt", flags, argc, argv, pam_getenv(pamh, "DEVICE"));
+	return PAM_SUCCESS;
+}
+
+PAM_EXTERN int pam_sm_open_session(pam_handle_t* pamh, int flags, int argc, const char** argv)
+{
+	log_pam("pam_sm_open_session", flags, argc, argv, pam_getenv(pamh, "DEVICE"));
+	return PAM_SUCCESS;
+}
+
+PAM_EXTERN int pam_sm_close_session(pam_handle_t* pamh, int flags, int argc, const char** argv)
+{
+	log_pam("pam_sm_close_session", flags, argc, argv, pam_getenv(pamh, "DEVICE"));
+	return PAM_SUCCESS;
+}
+
+PAM_EXTERN int pam_sm_chauthtok(pam_handle_t* pamh, int flags, int argc, const char** argv)
+{
+	log_pam("pam_sm_chauthtok", flags, argc, argv, pam_getenv(pamh, "DEVICE"));
+	return PAM_SUCCESS;
+}
diff --git a/pam_agl/pam_agl_usb.c b/pam_agl/pam_agl_usb.c
new file mode 100644
index 0000000..7afe73d
--- /dev/null
+++ b/pam_agl/pam_agl_usb.c
@@ -0,0 +1,186 @@
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <uuid/uuid.h>
+#include <json-c/json.h>
+
+#define PAM_SM_AUTH
+#define PAM_SM_ACCOUNT
+#define PAM_SM_SESSION
+#define PAM_SM_PASSWORD
+#include <security/pam_modules.h>
+#include <security/pam_appl.h>
+
+#define DATABASE_FILE "/etc/agl/keys.json"
+
+#define BLOCK_SIZE 4096
+typedef struct header_
+{
+	char mn[4];
+	size_t size;
+} header;
+
+int is_valid_mn(const char* v)
+{
+	return v && v[0] == 'I' && v[1] == 'D' && v[2] == 'K' && v[3] == 'Y';
+}
+
+int read_device(const char* device, char** idkey)
+{
+	int fd;
+	ssize_t sz;
+	header h;
+		
+	printf("[PAM DEBUG] check_device %s...\n", device);
+	fd = open(device, O_RDONLY);
+	if (fd == -1)
+	{
+		printf("[PAM DEBUG] Failed to open the device %s!\n", device);
+		return PAM_SERVICE_ERR;
+	}
+
+	sz = read(fd, &h, sizeof(header));
+	if (sz != sizeof(header) || !is_valid_mn(h.mn) || h.size < 1) { close(fd); printf("[PAM DEBUG]: bad header!\n"); return PAM_SERVICE_ERR; }
+	printf("[PAM DEBUG]: data size=%lu\n", h.size);
+
+	*idkey = (char*)malloc(h.size + 1);
+	if (!*idkey) { close(fd); printf("[PAM DEBUG] Bad alloc!\n"); return PAM_SERVICE_ERR; }
+
+	memset(*idkey, 0, h.size + 1);
+	sz = read(fd, *idkey, h.size);
+	close(fd);
+	if (sz != h.size) { free(idkey); printf("[PAM DEBUG] Bad data read!\n"); return PAM_SERVICE_ERR; }
+	return PAM_SUCCESS;
+}
+
+int authenticate(pam_handle_t* pamh, const char* uuid)
+{
+	struct json_object* database;
+	struct json_object* usb;
+	struct json_object* key;
+
+	database = json_object_from_file(DATABASE_FILE);
+	if (!database)
+	{
+		printf("[PAM DEBUG] Failed to parse the database\n");
+		return PAM_SERVICE_ERR;
+	}
+	
+	if (json_object_object_get_ex(database, "usb", &usb))
+	{	
+		if (json_object_object_get_ex(usb, uuid, &key))
+		{
+			printf("[PAM] Key found!\n");
+			printf("[PAM DEBUG] pam_set_item(\"%s\")\n", uuid);
+			pam_set_item(pamh, PAM_USER, uuid);
+				
+			const char* pam_authtok;
+			if (pam_get_item(pamh, PAM_AUTHTOK, (const void**)&pam_authtok) == PAM_SUCCESS && !pam_authtok)
+				pam_set_item(pamh, PAM_AUTHTOK, uuid);
+			
+			json_object_put(database);
+			return PAM_SUCCESS;
+		}
+	}
+	
+	printf("[PAM] Key not found!\n");
+	if (database) json_object_put(database);
+	return PAM_AUTH_ERR;
+}
+
+int check_device(pam_handle_t* pamh, const char* device)
+{
+	char* idkey;
+	int ret;
+	
+	ret = read_device(device, &idkey);
+	if (ret != PAM_SUCCESS) return ret;
+	
+	printf("[PAM DEBUG] Data read:\n%s\n", idkey);
+	
+	json_object* idkey_json = json_tokener_parse(idkey);
+	if (!idkey_json)
+	{
+		free(idkey);
+		printf("[PAM DEBUG] Failed to parse json data!\n");
+		return PAM_SERVICE_ERR;
+	}
+
+	json_object* uuid_json;
+	if(!json_object_object_get_ex(idkey_json, "uuid", &uuid_json))
+	{
+		free(idkey);
+		printf("[PAM DEBUG] The json does not contains a valid uuid\n");
+		return PAM_SERVICE_ERR;
+	}
+
+	const char* uuid = json_object_get_string(uuid_json);
+	printf("[PAM DEBUG] uuid: %s\n", uuid);
+	
+	ret = authenticate(pamh, uuid);
+	free(idkey);
+	json_object_put(idkey_json);
+	return ret;
+}
+
+void log_pam(const char* fname, int flags, int argc, const char** argv, const char* device)
+{
+	printf("[PAM DEBUG] ---------- %s ----------\n", fname);
+	printf("[PAM DEBUG] flags: %d\n", flags);
+	for(int i = 0; i < argc; ++i)
+	{
+		printf("[PAM DEBUG] argv[%d]: %s\n", i, argv[i]);
+	}
+	printf("[PAM DEBUG] device: %s\n", device);
+	printf("[PAM DEBUG] ----------------------------------------\n");
+}
+
+/*!
+	@brief The pam_sm_authenticate function is the service module's implementation
+	of the pam_authenticate(3) interface.
+	This function performs the task of authenticating the user.
+
+	@param[in] pamh Unknown.
+	@param[in] flags PAM_SILENT and/or PAM_DISALLOW_NULL_AUTHTOK.
+	@return PAM_SUCCESS if ok.
+*/
+PAM_EXTERN int pam_sm_authenticate(pam_handle_t* pamh, int flags, int argc, const char** argv)
+{
+	const char* device = pam_getenv(pamh, "DEVICE");
+	log_pam("pam_sm_authenticate", flags, argc, argv, device);
+	return check_device(pamh, device);
+}
+
+PAM_EXTERN int pam_sm_setcred(pam_handle_t* pamh, int flags, int argc, const char** argv)
+{
+	log_pam("pam_sm_setcred", flags, argc, argv, pam_getenv(pamh, "DEVICE"));
+	return PAM_SUCCESS;
+}
+
+PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t* pamh, int flags, int argc, const char** argv)
+{
+	log_pam("pam_sm_acct_mgmt", flags, argc, argv, pam_getenv(pamh, "DEVICE"));
+	return PAM_SUCCESS;
+}
+
+PAM_EXTERN int pam_sm_open_session(pam_handle_t* pamh, int flags, int argc, const char** argv)
+{
+	log_pam("pam_sm_open_session", flags, argc, argv, pam_getenv(pamh, "DEVICE"));
+	return PAM_SUCCESS;
+}
+
+PAM_EXTERN int pam_sm_close_session(pam_handle_t* pamh, int flags, int argc, const char** argv)
+{
+	log_pam("pam_sm_close_session", flags, argc, argv, pam_getenv(pamh, "DEVICE"));
+	return PAM_SUCCESS;
+}
+
+PAM_EXTERN int pam_sm_chauthtok(pam_handle_t* pamh, int flags, int argc, const char** argv)
+{
+	log_pam("pam_sm_chauthtok", flags, argc, argv, pam_getenv(pamh, "DEVICE"));
+	return PAM_SUCCESS;
+}
-- 
cgit