diff options
author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2011-09-20 07:18:56 +0000 |
---|---|---|
committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2011-09-20 07:18:56 +0000 |
commit | 3a3ed0cdcd5349969f3aee59a63cabd3439d7292 (patch) | |
tree | 3077a8b9c8aea19c2e70dbbd7bfd1639479fcc01 /src | |
parent | 0d92b905848f44fb794474412b4ca611c4bfd191 (diff) | |
download | smartcardauth-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/Makefile | 6 | ||||
-rw-r--r-- | src/smartauthmon.cpp | 721 |
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 &"); + } + } +} |