summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authortpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2011-09-20 07:18:56 +0000
committertpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2011-09-20 07:18:56 +0000
commit3a3ed0cdcd5349969f3aee59a63cabd3439d7292 (patch)
tree3077a8b9c8aea19c2e70dbbd7bfd1639479fcc01 /src
parent0d92b905848f44fb794474412b4ca611c4bfd191 (diff)
downloadsmartcardauth-3a3ed0cdcd5349969f3aee59a63cabd3439d7292.tar.gz
smartcardauth-3a3ed0cdcd5349969f3aee59a63cabd3439d7292.zip
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
Diffstat (limited to 'src')
-rw-r--r--src/Makefile6
-rw-r--r--src/smartauthmon.cpp721
2 files changed, 727 insertions, 0 deletions
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 &");
+ }
+ }
+}