From 3a3ed0cdcd5349969f3aee59a63cabd3439d7292 Mon Sep 17 00:00:00 2001
From: tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>
Date: Tue, 20 Sep 2011 07:18:56 +0000
Subject: Add an initial C++ port of the smartauthmon script to smartcardauth
 This still relies heavily on system calls, but is already faster and has the
 potential to be more secure

git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/smartcardauth@1254556 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
---
 src/Makefile         |   6 +
 src/smartauthmon.cpp | 721 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 727 insertions(+)
 create mode 100644 src/smartauthmon.cpp

diff --git a/src/Makefile b/src/Makefile
index e71a413..cd28008 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -9,8 +9,14 @@ xmalloc.o: xmalloc.c
 messages.o: messages.c
 	gcc messages.c -c
 
+smartauthmon.o: smartauthmon.cpp
+	g++ -I/usr/include/tqt -I/usr/include/qt3 smartauthmon.cpp -c
+
 ckpasswd: ckpasswd.o
 	gcc ckpasswd.o xmalloc.o messages.o -o ckpasswd -lpam -lcrypt
 
+ckpasswd: smartauthmon.o
+	gcc smartauthmon.o -o smartauthmon -ltqt
+
 clean: 
 	rm -f ckpasswd.o xmalloc.o messages.o ckpasswd
diff --git a/src/smartauthmon.cpp b/src/smartauthmon.cpp
new file mode 100644
index 0000000..5b8d029
--- /dev/null
+++ b/src/smartauthmon.cpp
@@ -0,0 +1,721 @@
+/* Smart Card TDE Authentication Script (c) 2010-2011 Timothy Pearson
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#define _XOPEN_SOURCE 500
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <termios.h>
+#include <signal.h>
+#include <ftw.h>
+
+#include <tqstring.h>
+#include <tqstringlist.h>
+
+// Maximum number of virtual terminals on this system
+#define MAXIMUM_VTS 49
+
+// The [secure] temporary directory for authentication
+#define SECURE_DIRECTORY_PATH "/tmp/smartauth"
+
+// Some internal constants
+#define CREATE_LIFE_CYCLE "01"
+
+static TQString secure_directory;
+static TQString command_mode;
+static TQString select_file;
+static TQString read_binary;
+static TQString update_binary;
+static TQString delete_file;
+static TQString get_challenge;
+static TQString external_auth;
+static TQString activate_file;
+
+static TQString hexidecimal_key;
+
+static TQString darray[MAXIMUM_VTS];
+
+static FILE* opensc_explorer_file;
+
+TQString readfile(const char * filename) {
+	FILE *fp;
+	long len;
+	char *buf;
+	fp=fopen(filename, "rb");
+	if (fp == NULL) {
+		printf("[WARNING] Unable to read from file %s\n\r", filename);
+		return TQString();
+	}
+	fseek(fp,0,SEEK_END);			// Seek to end
+	len=ftell(fp);				// Get position at end (length)
+	fseek(fp,0,SEEK_SET);			// Seek to beginning
+	buf=(char *)malloc(len);		// Malloc the buffer
+	fread(buf,len,1,fp);			// Read file
+	fclose(fp);
+	buf[len]=0;
+	TQString contents = TQString(buf);
+	free(buf);				// Free the buffer
+	return contents;
+}
+
+TQString exec(const char * cmd) {
+	TQString bashcommand = cmd;
+	bashcommand = bashcommand.replace("\"", "\\\"");
+	bashcommand = TQString("/bin/bash -c \"%1\"").tqarg(bashcommand);
+	FILE* pipe = popen(bashcommand.ascii(), "r");
+	if (!pipe) return "ERROR";
+	char buffer[128];
+	TQString result = "";
+	while(!feof(pipe)) {
+		if(fgets(buffer, 128, pipe) != NULL) {
+			result += buffer;
+		}
+	}
+	pclose(pipe);
+	result.remove(result.length(), 1);
+	return result;
+}
+
+int systemexec(const char * cmd) {
+	TQString bashcommand = cmd;
+	bashcommand = bashcommand.replace("\"", "\\\"");
+	bashcommand = TQString("/bin/bash -c \"%1\"").tqarg(bashcommand);
+	return system(bashcommand.ascii()) >> 8;
+}
+
+TQString execret(const char * cmd, int * retcode) {
+	TQString bashcommand = cmd;
+	bashcommand = bashcommand.replace("\"", "\\\"");
+	bashcommand = TQString("/bin/bash -c \"%1\"").tqarg(bashcommand);
+	FILE* pipe = popen(bashcommand.ascii(), "r");
+	if (!pipe) return "ERROR";
+	char buffer[128];
+	TQString result = "";
+	while(!feof(pipe)) {
+		if(fgets(buffer, 128, pipe) != NULL) {
+			result += buffer;
+		}
+	}
+	*retcode = pclose(pipe) >> 8;
+	result.remove(result.length(), 1);
+	return result;
+}
+
+int unlink_cb(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf)
+{
+	int rv = remove(fpath);
+	
+	if (rv)
+		perror(fpath);
+	
+	return rv;
+}
+
+int rmrf(const char *path)
+{
+	return nftw(path, unlink_cb, 64, FTW_DEPTH | FTW_PHYS);
+}
+
+TQString get_file(TQString prefix, TQString mode) {
+	if (command_mode == "acos") {
+		// Select EF prefix under DF 1000
+		systemexec((TQString("echo \"%1 %2\" > %3/query").tqarg(select_file).tqarg(prefix).tqarg(secure_directory)).ascii());
+		systemexec((TQString("scriptor %1/query 1> %2/response2").tqarg(secure_directory).tqarg(secure_directory)).ascii());
+		printf("[DEBUG 100.0] %s\n\r", readfile((TQString("%1/response2").tqarg(secure_directory))).ascii());
+
+		// Read binary
+		systemexec((TQString("echo \"%1\" > %2/query").tqarg(read_binary).tqarg(secure_directory)).ascii());
+		systemexec((TQString("scriptor %1/query 1> %2/response2").tqarg(secure_directory).tqarg(secure_directory)).ascii());
+		TQString authokresponse="90 00 : Normal processing";
+		TQString response1 = exec((TQString("cat %1/response2 | grep \"%2\")").tqarg(secure_directory).tqarg(authokresponse)).ascii());
+		if (response1 != "") {
+			systemexec((TQString("cat %1/response2 | tr -d '\n' > %1/response4").tqarg(secure_directory)).ascii());
+			TQString stringtoreplace="Using T=0 protocol00 B0 00 00 FF> 00 B0 00 00 FF< ";
+			TQString newstring="";
+			systemexec((TQString("sed -i \"s#%1#%2#g\" %3/response4").tqarg(stringtoreplace).tqarg(newstring).tqarg(secure_directory)).ascii());
+			stringtoreplace=" 90 00 : Normal processing.";
+			newstring="";
+			systemexec((TQString("sed -i \"s#%1#%2#g\" %3/response4").tqarg(stringtoreplace).tqarg(newstring).tqarg(secure_directory)).ascii());
+			if (mode == "text") {
+				stringtoreplace=" 00";
+				newstring="";
+				systemexec((TQString("sed -i \"s#%1#%2#g\" %3/response4").tqarg(stringtoreplace).tqarg(newstring).tqarg(secure_directory)).ascii());
+			}
+			printf("[DEBUG 100.1] %s\n\r", readfile((TQString("%1/response4").tqarg(secure_directory))).ascii());
+			unlink((TQString("%1/lukskey").tqarg(secure_directory)).ascii());
+			systemexec((TQString("xxd -r -p %1/response4 %1/lukskey").tqarg(secure_directory)).ascii());
+			return(TQString("%1/lukskey").tqarg(secure_directory));
+		}
+	}
+
+	if (command_mode == "cryptoflex") {
+		TQString file = TQString(prefix).replace(' ', "");
+		unlink((TQString("3F00_%1").tqarg(file)).ascii());
+// 		systemexec((TQString("echo \"get %1\" | opensc-explorer").tqarg(file)).ascii());
+		fputs((TQString("get %1\n").tqarg(file)).ascii(), opensc_explorer_file);
+		fflush(opensc_explorer_file);
+		int j;
+		// Wait up to 2 seconds for the file to be written
+		for (j=0;j<200;j++) {
+			FILE* fp1 = fopen((TQString("3F00_%1").tqarg(file)).ascii(), "r");
+			if (fp1) {
+				// file exists
+				fclose(fp1);
+				break;
+			}
+			usleep(10000);
+		}
+		usleep(100000);	// [FIXME] Here I assume that the entire file will be written (after it was created) within 100us.  This may not be correct in all cases!
+		return TQString("3F00_%1").tqarg(file);
+	}
+}
+
+void createfile(TQString prefix, TQString mode)
+{
+	if (command_mode == "cryptoflex") {
+		// Create transparent file with permissions:
+		// delete, terminate, activate, deactivate, update, read for Key 1 and Key 2 only
+		systemexec((TQString("echo \"F0 E0 00 FF 10 FF FF 00 %1 %2 01 3F 44 FF 44 01 03 11 FF 11\" > %3/query").tqarg(prefix).tqarg(mode).tqarg(secure_directory)).ascii());
+		systemexec((TQString("scriptor %1/query 1> %2/response2 2>/dev/null").tqarg(secure_directory).tqarg(secure_directory)).ascii());
+	}
+
+	if (command_mode == "acos") {
+		// Create transparent file with permissions:
+		// delete, terminate, activate, deactivate, update, read for Key 1, Key 2, and Key 3 only (SE 04)
+		// created in DF 1000 under MF, SE file is 10FE
+		//                      SIZE           TRANSPARENT
+
+		systemexec((TQString("echo \"00 E0 00 00 1A 62 18 80 02 00 %1 82 01 01 83 02 %2 8A 01 %3 8C 08 7F 04 04 04 04 04 04 04\" > %4/query").tqarg(prefix).tqarg(mode).tqarg(CREATE_LIFE_CYCLE).tqarg(secure_directory)).ascii());
+		systemexec((TQString("scriptor %1/query 1> %2/response2 2>/dev/null").tqarg(secure_directory)).ascii());
+		printf("[DEBUG 300.0] %s\n\r", readfile((TQString("%1/response2").tqarg(secure_directory))).ascii());
+	}
+}
+
+void update_file(TQString prefix, TQString mode) {
+	if (command_mode == "acos") {
+		// Select EF prefix under DF 1000
+		systemexec((TQString("echo \"$SELECT_FILE %1\" > %2/query").tqarg(prefix).tqarg(secure_directory)).ascii());
+		systemexec((TQString("scriptor %1/query 1> %2/response2").tqarg(secure_directory).tqarg(secure_directory)).ascii());
+		printf("[DEBUG 200.0] %s\n\r", readfile((TQString("%1/response2").tqarg(secure_directory))).ascii());
+
+		// Update existing file
+		// Zero pad input file
+		systemexec((TQString("dd if=/dev/zero of=%1/response2 bs=1 count=255 2>/dev/null 1>/dev/null").tqarg(secure_directory)).ascii());
+		systemexec((TQString("dd if=%1 of=%2/response2 bs=1 count=255 conv=notrunc 2>/dev/null 1>/dev/null").tqarg(mode).tqarg(secure_directory)).ascii());
+
+		// Truncate to 255 bytes and expand to standard hex listing format
+		systemexec((TQString("xxd -l 255 -ps -c 1 %1/response2 > %2/response").tqarg(secure_directory).tqarg(secure_directory)).ascii());
+		systemexec((TQString("cat %1/response | tr '\n' ' ' > %1/hexready").tqarg(secure_directory)).ascii());
+		TQString hexready = readfile((TQString("%1/hexready").tqarg(secure_directory)).ascii());
+		systemexec((TQString("echo \"%1 %2\" > %3/query").tqarg(update_binary).tqarg(hexready).tqarg(secure_directory)).ascii());
+		systemexec((TQString("scriptor %1/query 1> %2/response2 2>/dev/null").tqarg(secure_directory).tqarg(secure_directory)).ascii());
+		printf("[DEBUG 200.1] %s\n\r", readfile((TQString("%1/response2").tqarg(secure_directory))).ascii());
+	}
+
+	if (command_mode == "cryptoflex") {
+		// Delete old file
+		systemexec((TQString("echo \"%1 $1\" > %2/query").tqarg(delete_file).tqarg(secure_directory)).ascii());
+		systemexec((TQString("scriptor %1/query 1> %2/response2 2>/dev/null").tqarg(secure_directory).tqarg(secure_directory)).ascii());
+		printf("[DEBUG 200.2] %s\n\r", readfile((TQString("%1/response2").tqarg(secure_directory))).ascii());
+		
+		// Create new file
+		createfile("FF", prefix);
+		TQString file = TQString(prefix).replace(' ', "");
+		systemexec((TQString("echo \"put %1 %2\" | opensc-explorer").tqarg(file).tqarg(mode)).ascii());
+	}
+}
+
+int main (int argc, char *argv[])
+{
+	TQString smartcard_username;
+	TQString oldsmartcard_username;
+	TQString smartcard_slave;
+	TQString lverify;
+	TQString cverify;
+	TQString udisplay;
+	TQString newdisplay;
+	TQString logouttest;
+	TQString blankresult;
+	TQString smartcard_minutes_raw;
+
+	int timer;
+	int smartcard_minutes;
+	int internet_minutes;
+	int newdisplayint;
+
+	// Create the secure directory and lock it down
+	secure_directory = SECURE_DIRECTORY_PATH;
+	rmrf(secure_directory.ascii());
+	mkdir(secure_directory.ascii(), 600);
+	chown(secure_directory.ascii(), 0, 0);
+	chmod(secure_directory.ascii(), 600);
+	secure_directory=exec("mktemp " SECURE_DIRECTORY_PATH "/smartauthmon.XXXXXXXXXX");
+	secure_directory.replace('\n', "");
+	rmrf(secure_directory.ascii());
+	mkdir(secure_directory.ascii(), 600);
+	chown(secure_directory.ascii(), 0, 0);
+	chmod(secure_directory.ascii(), 600);
+
+	// Restart PCSCD and kill spurious processes
+	systemexec("killall -9 pcscd 2>/dev/null 1>/dev/null");
+	systemexec("/etc/init.d/pcscd restart 2>/dev/null 1>/dev/null");
+	systemexec("/etc/init.d/pcscd-nodbus restart 2>/dev/null 1>/dev/null");
+
+	// See if required programs are installed
+	TQString scriptor = exec("whereis scriptor");
+	if ( scriptor == "scriptor:" ) {
+		printf("ERROR: scriptor is not installed!  This program cannot continue!\n\r");
+		return 1;
+	}
+	TQString opensc = exec("whereis opensc-explorer");
+	if ( opensc == "opensc-explorer:" ) {
+		printf("ERROR: opensc-explorer is not installed!  This program cannot continue!\n\r");
+		return 1;
+	}
+
+	oldsmartcard_username="";
+	printf("[DEBUG 400.0] Ready...\n\r");
+	while (1) {
+		sleep(1);
+		int output = systemexec("echo \"exit\" | scriptor 2>/dev/null 1>/dev/null");
+		if (output == 0) {
+			printf("[DEBUG 400.1] Card inserted!\n\r");
+			systemexec("echo \"TAuthenticating SmartCard...\" > /tmp/ksocket-global/kdesktoplockcontrol &");
+	
+			// Get card ATR
+			systemexec((TQString("echo \"RESET\" > %1/query").tqarg(secure_directory)).ascii());
+			systemexec((TQString("scriptor %1/query 1> %2/response2").tqarg(secure_directory).tqarg(secure_directory)).ascii());
+			TQString authokresponse="OK: ";
+			TQString response1 = exec((TQString("cat %1/response2 | grep \"%2\"").tqarg(secure_directory).tqarg(authokresponse)).ascii());
+			if (response1 != "") {
+				systemexec((TQString("cat %1/response2 | tr -d '\n' > %2/response4").tqarg(secure_directory).tqarg(secure_directory)).ascii());
+				TQString stringtoreplace="Using T=0 protocolRESET> RESET< OK: ";
+				TQString newstring="";
+				systemexec((TQString("sed -i \"s#%1#%2#g\" %3/response4").tqarg(stringtoreplace).tqarg(newstring).tqarg(secure_directory)).ascii());
+				TQString smartatr = readfile((TQString("%1/response4").tqarg(secure_directory)).ascii());
+				printf("[DEBUG 400.2] Got ATR: %s\n\r", smartatr.ascii());
+				if (smartatr == "3B BE 18 00 00 41 05 10 00 00 00 00 00 00 00 00 00 90 00 ") {
+					printf("[DEBUG 400.3] Detected ACOS5 card\n\r");
+					command_mode="acos";
+				}
+				if (smartatr == "3B 02 14 50 ") {
+					printf("[DEBUG 400.3] Detected Schlumberger CryptoFlex card\n\r");
+					command_mode="cryptoflex";
+				}
+			}
+			else {
+				printf("[DEBUG 400.3] No card detected!\n\r");
+			}
+			
+			if (command_mode == "cryptoflex") {
+				get_challenge="C0 84 00 00 08";
+				external_auth="C0 82 00 00 07 01";
+				select_file="C0 A4 00 00 02";
+				delete_file="F0 E4 00 00 02";
+			}
+			
+			if (command_mode == "acos") {
+				get_challenge="00 84 00 00 08";
+				external_auth="00 82 00 82 08";		// Key 2
+				select_file="00 A4 00 00 02";
+				delete_file="00 E4 00 00 00";
+				read_binary="00 B0 00 00 FF";
+				update_binary="00 D6 00 00 FF";
+				activate_file="00 44 00 00 02";
+			}
+	
+			// Authenticate card
+	
+			if (command_mode == "acos") {
+				// Select MF
+				systemexec((TQString("echo \"00 A4 00 00 00\" > %1/query").tqarg(secure_directory)).ascii());
+				systemexec((TQString("scriptor %1/query 1> %2/response2").tqarg(secure_directory).tqarg(secure_directory)).ascii());
+				printf("[DEBUG 400.4] %s\n\r", readfile((TQString("%1/response2").tqarg(secure_directory))).ascii());
+			
+				// Select DF 1000 under MF
+				systemexec((TQString("echo \"%1 10 00\" > %2/query").tqarg(select_file).tqarg(secure_directory)).ascii());
+				systemexec((TQString("scriptor %1/query 1> %2/response2").tqarg(secure_directory).tqarg(secure_directory)).ascii());
+				printf("[DEBUG 400.5] %s\n\r", readfile((TQString("%1/response2").tqarg(secure_directory))).ascii());
+			}
+	
+			systemexec((TQString("echo %1 > %2/authscript").tqarg(get_challenge).tqarg(secure_directory)).ascii());
+	
+			systemexec((TQString("scriptor %1/authscript | grep 'Normal processing' > %2/challenge").tqarg(secure_directory).tqarg(secure_directory)).ascii());
+			systemexec((TQString("perl -pi -e 's/ //g' %1/challenge").tqarg(secure_directory)).ascii());
+			systemexec((TQString("perl -pi -e 's/:Normalprocessing.//g' %1/challenge").tqarg(secure_directory)).ascii());
+			systemexec((TQString("perl -pi -e 's/<//g' %1/challenge").tqarg(secure_directory)).ascii());
+			systemexec((TQString("xxd -r -p %1/challenge %2/challenge").tqarg(secure_directory).tqarg(secure_directory)).ascii());
+	
+			// Now DES encrypt the challenge
+			// Later, change the initialization vector to random if possible
+
+			// Read hexidecimal_key from the system crypto files and create the response from the challenge
+			hexidecimal_key = readfile("/etc/smartauth/smartauthmon.key");
+			hexidecimal_key.replace('\n', "");
+			systemexec((TQString("openssl des-ecb -in %1/challenge -out %2/response -K %3 -iv 1").tqarg(secure_directory).tqarg(secure_directory).tqarg(hexidecimal_key)).ascii());
+	
+			if (command_mode == "acos") {
+				// Truncate to 8 bytes
+				systemexec((TQString("dd if=%1/response of=%2/response2 bs=1 count=8 2>/dev/null 1>/dev/null").tqarg(secure_directory).tqarg(secure_directory)).ascii());
+	
+				// Expand to standard hex listing format
+				systemexec((TQString("xxd -g 1 %1/response2 %2/response").tqarg(secure_directory).tqarg(secure_directory)).ascii());
+				systemexec((TQString("dd if=%1/response of=%2/response2 bs=1 count=23 skip=9 2>/dev/null 1>/dev/null").tqarg(secure_directory).tqarg(secure_directory)).ascii());
+			}
+	
+			if (command_mode == "cryptoflex") {
+				// Truncate to 6 bytes
+				systemexec((TQString("dd if=%1/response of=%2/response2 bs=1 count=6 2>/dev/null 1>/dev/null").tqarg(secure_directory).tqarg(secure_directory)).ascii());
+	
+				// Expand to standard hex listing format
+				systemexec((TQString("xxd -g 1 %1/response2 %2/response").tqarg(secure_directory).tqarg(secure_directory)).ascii());
+				systemexec((TQString("dd if=%1/response of=%2/response2 bs=1 count=17 skip=9 2>/dev/null 1>/dev/null").tqarg(secure_directory).tqarg(secure_directory)).ascii());
+			}
+	
+			// Assemble the response file
+			TQString response2 = readfile((TQString("%1/response2").tqarg(secure_directory)).ascii());
+			response1 = TQString("%1 %2").tqarg(external_auth).tqarg(response2);
+			systemexec((TQString("echo %1 > %2/response").tqarg(response1).tqarg(secure_directory)).ascii());
+	
+			// Send the response!
+			systemexec((TQString("scriptor %1/response > %2/response2").tqarg(secure_directory).tqarg(secure_directory)).ascii());
+	
+			// Get the result
+			authokresponse = "< 90 00 : Normal processing";
+			response1 = exec((TQString("cat %1/response2 | grep \"%2\"").tqarg(secure_directory).tqarg(authokresponse)).ascii());
+			printf("[DEBUG 400.6] %s\n\r", response1.ascii());
+			if (response1 != "") {
+				printf("[DEBUG 400.7] Smart card validation successfull!\n\r");
+				if (command_mode == "cryptoflex") {
+					opensc_explorer_file = popen("opensc-explorer 2>/dev/null 1>/dev/null", "w");
+				}
+				// Get username and password
+				TQString response = get_file("10 02", "text");
+				smartcard_username = readfile(response);
+				response = get_file("10 03", "text");
+				systemexec((TQString("mv %1 %2/password").tqarg(response).tqarg(secure_directory)).ascii());
+				response = get_file("10 04", "text");
+				smartcard_slave = readfile(response);
+				if (smartcard_slave == "SLAVE") {
+					get_file("10 05", "text");
+					smartcard_minutes_raw = readfile(response);
+					get_file("10 06", "text");
+					internet_minutes = readfile(response).toInt();
+				}
+			}
+			else {
+				printf("[DEBUG 400.7] This card does not recognize this system!\n\r");
+				systemexec("echo \"EInvalid SmartCard Inserted\" > /tmp/ksocket-global/kdesktoplockcontrol &");
+				sleep(1);
+				smartcard_username="";
+				unlink((TQString("%1/password").tqarg(secure_directory)).ascii());
+				smartcard_slave="";
+			}
+	
+			if (smartcard_slave == "SLAVE") {
+				if (smartcard_minutes_raw == "") {
+					smartcard_minutes=1;
+				}
+				else {
+					smartcard_minutes = smartcard_minutes_raw.toInt();
+				}
+	
+				// Decrement minutes on card
+				if (smartcard_minutes > 0) {
+					smartcard_minutes=smartcard_minutes-1;
+					systemexec((TQString("echo %1 > %2/minutes").tqarg(smartcard_minutes).tqarg(secure_directory)).ascii());
+					update_file("10 05", TQString("%1/minutes").tqarg(secure_directory));
+				}
+	
+				if (smartcard_minutes == 0) {
+					printf("[DEBUG 400.8] Minutes have been used up!\n\r");
+					// Prohibit logon
+					smartcard_username="";
+					unlink((TQString("%1/password").tqarg(secure_directory)).ascii());
+				}
+	
+				mkdir("/etc/smartmon", 644);
+				systemexec((TQString("echo %1 > /etc/smartmon/minutesremaining").tqarg(smartcard_minutes)).ascii());
+				chmod("/etc/smartmon/minutesremaining", 755);
+			}
+	
+			// Initialize variables
+			int loginok=1;
+	
+			// Try to do the authentication
+			TQString result="";
+			int timeout=0;
+			int errcode=0;
+			int waserror=0;
+			int noactivesessions=0;
+	
+			result = exec("/opt/trinity/bin/kdmctl -g list");
+			if (result == "ok") {
+				noactivesessions=1;
+				result="okbutempty";
+			}
+			printf("[DEBUG 400.9] %s\n\r", result.ascii());
+			TQString resultbkp=result;
+	
+			if (errcode == 0) {
+				// Allow KDM to finish starting
+				if (waserror == 1) {
+					sleep(10);
+				}
+				
+				// Zero the desktop array
+				int index=0;
+				while (index < MAXIMUM_VTS) {
+					darray[index]="";
+					index++;
+				}
+	
+				if (result != "okbutempty") {
+					TQStringList sessionList = TQStringList::split('\t', result, false);
+					for ( TQStringList::Iterator it = sessionList.begin(); it != sessionList.end(); ++it ) {
+						TQStringList sessionInfoList = TQStringList::split(',', *it, true);
+						if ((*(sessionInfoList.at(0))).startsWith(":")) {
+							darray[(*(sessionInfoList.at(0))).mid(1).toInt()] = (*(sessionInfoList.at(2)));
+						}
+					}
+				}
+			
+				// See if the desired user is already logged in
+				index=0;
+				int foundsession=0;
+				while (index < MAXIMUM_VTS) {
+					if (darray[index] == smartcard_username) {
+						if (darray[index] != "") {
+							printf("[DEBUG 400.a] Found existing session on desktop: %d\n\r", index);
+							foundsession=1;
+							// Check password
+							// FIXME
+							// This might expose the password for an instant
+							// Integrate the password checking from "ckpasswd.c" here instead
+							lverify = exec((TQString("/usr/bin/smartauthckpasswd -u %1 -p $(cat %2/password)").tqarg(darray[index]).tqarg(secure_directory)).ascii());
+							cverify = TQString("User:%1").tqarg(darray[index]);
+							udisplay = TQString(":%1").tqarg(index);
+							if (lverify == cverify) {
+								systemexec((TQString("su %1 -c \"export DISPLAY=%2; /opt/trinity/bin/dcop kdesktop KScreensaverIface quit\"").tqarg(smartcard_username).tqarg(udisplay)).ascii());
+								systemexec((TQString("su %1 -c \"export DISPLAY=%2; /opt/trinity/bin/dcop kdesktop KScreensaverIface enable false\"").tqarg(smartcard_username).tqarg(udisplay)).ascii());
+								systemexec((TQString("/opt/trinity/bin/kdmctl activate %1").tqarg(udisplay)).ascii());
+							}
+							else {
+								systemexec("echo \"EUnauthorized SmartCard Inserted\" > /tmp/ksocket-global/kdesktoplockcontrol &");
+							}
+						}
+						else {
+							printf("[DEBUG 400.b] Username not specified\n\r");
+							foundsession=2;
+							sleep(1);
+						}
+					}
+					index++;
+				}
+			
+				if (foundsession == 0) {
+					printf("[DEBUG 400.c] Existing session not found, starting new...\n\r");
+					
+					// Make sure that this is not display :0 (default login screen).
+					// If it is, execute login.  If not, create new session, then execute login
+					int usebasedisplay=0;
+					if (noactivesessions == 1) {
+						newdisplay = exec("ls /var/run/xdmctl/ | grep 'xdmctl-:0'");
+						printf("[DEBUG 400.d] %s\n\r", newdisplay.ascii());
+						if (newdisplay != "") {
+							usebasedisplay=1;
+						}
+					}
+					if (!resultbkp.contains(",vt")) {
+						newdisplay = exec("ls /var/run/xdmctl/ | grep 'xdmctl-:0'");
+						printf("[DEBUG 400.d] %s\n\r", newdisplay.ascii());
+						if (newdisplay != "") {
+							usebasedisplay=1;
+						}
+					}
+	
+					printf("[DEBUG 400.e] Creating new session\n\r");
+					// Attempt login
+	
+					// Find next sequential inactive display
+					// FIXME
+					// This assumes the original VT is on display 0 at all times
+					int minvt = 0;
+					TQStringList sessionList = TQStringList::split('\t', result, false);
+					for (newdisplayint = minvt; newdisplayint<MAXIMUM_VTS; newdisplayint++) {
+						bool displayfound = false;
+						for ( TQStringList::Iterator it = sessionList.begin(); it != sessionList.end(); ++it ) {
+							TQStringList sessionInfoList = TQStringList::split(',', *it, true);
+							if ((*(sessionInfoList.at(0))).startsWith(TQString(":%1").tqarg(newdisplayint))) {
+								displayfound = true;
+							}
+						}
+						if (displayfound == false) {
+							break;
+						}
+					}
+	
+					newdisplay = TQString(":%1").tqarg(newdisplayint);
+					printf("[DEBUG 400.f] The next display to start will be %s\n\r", newdisplay.ascii());
+						
+					systemexec("/opt/trinity/bin/kdmctl -g reserve");
+					systemexec((TQString("/opt/trinity/bin/kdmctl -g login %1 now %2 $(cat %3/password)").tqarg(newdisplay).tqarg(smartcard_username).tqarg(secure_directory)).ascii());
+					sleep(2);
+					systemexec((TQString("/opt/trinity/bin/kdmctl -g activate %1").tqarg(newdisplay)).ascii());
+					udisplay=newdisplay;
+				}
+	
+				if (smartcard_slave == "SLAVE") {
+					if (smartcard_minutes < 5) {
+						systemexec((TQString("su %1 -c \"export DISPLAY=%2; zenity --warning --text 'You have less than 5 minutes of computer time remaining' || exit 0\" &").tqarg(smartcard_username).tqarg(udisplay)).ascii());
+					}
+				}
+		
+				unlink((TQString("%1/password").tqarg(secure_directory)).ascii());
+		
+				// if (loginok == 1) {
+					// Wait for SmartCard removal
+					systemexec("echo \"C\" > /tmp/ksocket-global/kdesktoplockcontrol &");
+					timer=60;
+					output=0;
+					
+					while (output == 0) {
+						sleep(1);
+						systemexec((TQString("su %1 -c \"export DISPLAY=%2; /opt/trinity/bin/dcop kdesktop KScreensaverIface quit\"").tqarg(smartcard_username).tqarg(udisplay)).ascii());
+						systemexec((TQString("su %1 -c \"export DISPLAY=%2; /opt/trinity/bin/dcop kdesktop KScreensaverIface enable false\"").tqarg(smartcard_username).tqarg(udisplay)).ascii());
+						output = systemexec("echo \"exit\" | scriptor 2>/dev/null 1>/dev/null");
+						if (smartcard_slave == "SLAVE") {
+							timer--;
+							if (timer == 0) {
+								// 60 seconds have passed, decrement minutes on card
+								smartcard_minutes--;
+								systemexec((TQString("echo %1 > /etc/smartmon/minutesremaining").tqarg(smartcard_minutes)).ascii());
+								chmod("/etc/smartmon/minutesremaining", 755);
+		
+								timer=60;
+	
+								systemexec((TQString("echo %1 > %2/minutes").tqarg(smartcard_minutes).tqarg(secure_directory)).ascii());
+								update_file("10 05", TQString("%1/minutes").tqarg(secure_directory));
+					
+								if (smartcard_minutes == 0) {
+									printf("[DEBUG 401.0] Minutes have been used up!\n\r");
+									// Prohibit logon
+									smartcard_username="";
+									unlink((TQString("%1/password").tqarg(secure_directory)).ascii());
+								}
+					
+								mkdir("/etc/smartmon", 644);
+								systemexec((TQString("echo %1 > /etc/smartmon/minutesremaining").tqarg(smartcard_minutes)).ascii());
+								chmod("/etc/smartmon/minutesremaining", 755);
+	
+								if (smartcard_minutes == 5) {
+									systemexec((TQString("su %1 -c \"export DISPLAY=%2; zenity --warning --text 'You have less than 5 minutes of computer time remaining' || exit 0\" &").tqarg(smartcard_username).tqarg(udisplay)).ascii());
+								}
+		
+								if (smartcard_minutes == 0) {
+									printf("[DEBUG 401.1] Minutes have been used up!\n\r");
+									printf("[DEBUG 401.2] Beginning logoff process\n\r");
+									output=254;
+								}
+							}
+						}
+					}
+	
+					printf("[DEBUG 401.3] Card removed\n\r");
+			
+					// Is the user still logged in?
+					result="ok";
+					timeout=0;
+					errcode=0;
+					result = exec("/opt/trinity/bin/kdmctl -g list");
+					if (result == "ok") {
+						noactivesessions=1;
+						result="okbutempty";
+					}
+					printf("[DEBUG 401.4] %s\n\r", result.ascii());
+					
+					// Zero the desktop array
+					index=0;
+					while (index < MAXIMUM_VTS) {
+						darray[index]="";
+						index++;
+					}
+				
+					TQStringList sessionList = TQStringList::split('\t', result, false);
+					for ( TQStringList::Iterator it = sessionList.begin(); it != sessionList.end(); ++it ) {
+						TQStringList sessionInfoList = TQStringList::split(',', *it, true);
+						if ((*(sessionInfoList.at(0))).startsWith(":")) {
+							darray[(*(sessionInfoList.at(0))).mid(1).toInt()] = (*(sessionInfoList.at(2)));
+						}
+					}
+	
+					// See if the desired user is still logged in
+					index=0;
+					foundsession=0;
+					while (index != MAXIMUM_VTS) {
+						if (darray[index] == smartcard_username) {
+							if (darray[index] != "") {
+								printf("[DEBUG 401.5] Found existing session on desktop: %d\n\r", index);
+								udisplay = TQString(":%1").tqarg(index);
+								foundsession=1;
+								errcode=1;
+								timeout=0;
+								blankresult="";
+								while (blankresult != "true") {
+									systemexec((TQString("/opt/trinity/bin/kdmctl -g activate %1").tqarg(udisplay)).ascii());
+									systemexec((TQString("su %1 -c \"export DISPLAY=%2; /opt/trinity/bin/dcop kdesktop KScreensaverIface enable true\"").tqarg(smartcard_username).tqarg(udisplay)).ascii());
+									systemexec((TQString("su %1 -c \"export DISPLAY=%2; /opt/trinity/bin/dcop kdesktop KScreensaverIface lock\"").tqarg(smartcard_username).tqarg(udisplay)).ascii());
+									int retcode;
+									blankresult = execret(TQString("su %1 -c \"export DISPLAY=%2; /opt/trinity/bin/dcop kdesktop KScreensaverIface isBlanked\"").tqarg(smartcard_username).tqarg(udisplay).ascii(), &retcode);
+									if (retcode != 0) {
+										blankresult="true";
+									}
+									logouttest = exec((TQString("echo %1 | grep 'target display has no VT assigned'").tqarg(blankresult)).ascii());
+									if (logouttest != "") {
+										printf("[DEBUG 401.6] User has logged out\n\r");
+										blankresult="true";
+									}
+								}
+							}
+							else {
+								printf("[DEBUG 401.7] Username not specified!\n\r");
+								sleep(1);
+							}
+						}
+						index++;
+					}
+				// }
+			}
+
+			if (command_mode == "cryptoflex") {
+				pclose(opensc_explorer_file);
+			}
+	
+			smartcard_username="";
+			unlink("/etc/smartmon/minutesremaining");
+			systemexec("echo \"C\" > /tmp/ksocket-global/kdesktoplockcontrol &");
+		}
+	}
+}
-- 
cgit v1.2.3

