From cbe66c290b343f54a6741cb420bac17225d51285 Mon Sep 17 00:00:00 2001
From: tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>
Date: Thu, 22 Sep 2011 19:47:58 +0000
Subject: Make smartauthmon use new kdm control sockets This stabilizes login
 with smart cards on finicky Xorg servers

git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/smartcardauth@1255016 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
---
 Makefile                    |   1 -
 src/smartauth_displayfinder |  30 --------
 src/smartauthmon.cpp        | 183 ++++++++++++++++++++++++++++++--------------
 3 files changed, 127 insertions(+), 87 deletions(-)
 delete mode 100755 src/smartauth_displayfinder

diff --git a/Makefile b/Makefile
index 2301ea0..9259b90 100755
--- a/Makefile
+++ b/Makefile
@@ -16,7 +16,6 @@ install:
 	mkdir -p $(DESTDIR)/usr
 	cp -Rp src/ckpasswd usr/bin/smartauthckpasswd
 	cp -Rp src/smartauthmon usr/bin/smartauthmon
-	cp -Rp src/smartauth_displayfinder usr/bin/smartauth_displayfinder
 	cp -Rp usr/*  $(DESTDIR)/usr/
 
 	mkdir -p $(DESTDIR)/etc
diff --git a/src/smartauth_displayfinder b/src/smartauth_displayfinder
deleted file mode 100755
index cbe9dec..0000000
--- a/src/smartauth_displayfinder
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/bin/bash								
-
-mkdir -p /tmp/smartauthmon/						
-ls /var/run/xdmctl > /tmp/smartauthmon/originalxdm			
-										
-# Set loop separator to end of line					
-BAKIFS=$IFS								
-IFS=$(echo -en "\n\b")						
-exec 3<&0								
-exec 0</tmp/smartauthmon/originalxdm					
-newdisplayfound=0							
-newdisplay=-1								
-while read -r line							
-do									
-	# use $line variable to process lines				
-	line=$(echo $line | grep 'xdmctl-:' | sed -e 's/xdmctl-://')	
-	if [ "`expr $line - $line 2>/dev/null`" == "0" ]; then	
-		echo "Found active display on $line"			
-		if [[ $newdisplayfound -eq 0 ]]; then			
-			tempnewdisplay=$((newdisplay + 1))		
-			if [[ $line -eq $tempnewdisplay ]]; then	
-				echo "Sequential display $line found after display $newdisplay..."
-				newdisplay=$line			
-			fi						
-		fi							
-	fi								
-done									
-exec 0<&3								
-newdisplay=$(($newdisplay + 1))					
-rm -rf /tmp/smartauthmon/						
diff --git a/src/smartauthmon.cpp b/src/smartauthmon.cpp
index 3c5dd98..88bccee 100644
--- a/src/smartauthmon.cpp
+++ b/src/smartauthmon.cpp
@@ -31,6 +31,7 @@
 #include <signal.h>
 #include <ftw.h>
 
+#include <tqdir.h>
 #include <tqstring.h>
 #include <tqstringlist.h>
 
@@ -46,7 +47,9 @@
 // Some internal constants
 #define CREATE_LIFE_CYCLE "01"
 
-#define tqarg arg
+#define KDM_CONTROL_FIFO_DIR "/tmp/ksocket-global/kdm"
+#define KDM_CONTROL_FIFO_FILE "/tmp/ksocket-global/kdm/kdmctl-%1"
+#define KDM_CONTROL_FIFO_SAK_FILE "/tmp/ksocket-global/kdm/kdmctl-sak-%1"
 
 // In ckpass.o
 extern "C" {
@@ -69,6 +72,17 @@ static TQString darray[MAXIMUM_VTS];
 
 static FILE* opensc_explorer_file;
 
+struct sigaction usr_action;
+sigset_t block_mask;
+
+void handle_sigpipe(int sig)
+{
+	int uidnum;
+	if (sig == SIGPIPE) {
+		printf("Got SIGPIPE!\n\r"); fflush(stdout);
+	}
+}
+
 TQString readfile(const char * filename) {
 	FILE *fp;
 	long len;
@@ -90,6 +104,20 @@ TQString readfile(const char * filename) {
 	return contents;
 }
 
+int writefile(const char * filename, TQString contents) {
+	int fp;
+	long len;
+	char *buf;
+	fp=open(filename, O_WRONLY | O_NONBLOCK);
+	if (fp < 0) {
+		printf("[WARNING] Unable to open file %s for writing\n\r", filename); fflush(stdout);
+		return -1;
+	}
+	int retcode = write(fp, contents.ascii(), contents.length());
+	close(fp);
+	return retcode;
+}
+
 TQString exec(const char * cmd) {
 	TQString bashcommand = cmd;
 	bashcommand = bashcommand.replace("\"", "\\\"");
@@ -278,6 +306,13 @@ int main (int argc, char *argv[])
 
         printf("[DEBUG 390.0] Starting up\n\r"); fflush(stdout);
 
+	// Initialize signal handlers
+	sigfillset(&block_mask);
+	usr_action.sa_handler = handle_sigpipe;
+	usr_action.sa_mask = block_mask;
+	usr_action.sa_flags = 0;
+	sigaction(SIGPIPE, &usr_action, NULL);
+
 	// Create the secure directory and lock it down
 	secure_directory = SECURE_DIRECTORY_PATH;
 	rmrf(secure_directory.ascii());
@@ -565,68 +600,104 @@ int main (int argc, char *argv[])
 				if (foundsession == 0) {
 					printf("[DEBUG 400.c] Existing session not found, starting new...\n\r"); fflush(stdout);
 
-					// 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()); fflush(stdout);
-						if (newdisplay != "") {
-							usebasedisplay=1;
+					// Get directory listing of kdm control socket directory
+					// Also start new X server if needed
+					bool have_valid_display = false;
+					bool display_has_sak = false;
+					bool writeerror = false;
+					newdisplayint = MAXIMUM_VTS+1;
+					while (have_valid_display == false) {
+						display_has_sak = false;
+						writeerror = false;
+						TQDir dr(KDM_CONTROL_FIFO_DIR);
+						dr.setFilter( TQDir::System );
+						dr.setSorting( TQDir::Name );
+						const TQFileInfoList *list = dr.entryInfoList();
+						if (list) {
+							TQFileInfoListIterator it( *list );
+							TQFileInfo *fi;
+							while ( (fi = it.current()) != NULL ) {
+								bool isint;
+								int tempdisplayint;
+								TQString tempdisplaystr;
+								tempdisplaystr = fi->fileName();
+								printf( "%s\n", fi->fileName().latin1() ); fflush(stdout);
+								if (fi->fileName().tqcontains("kdmctl-sak-")) {
+									tempdisplaystr = tempdisplaystr.replace("kdmctl-sak-", "");
+									tempdisplayint = tempdisplaystr.toInt(&isint);
+									if (isint) {
+										if (tempdisplayint < newdisplayint) {
+											newdisplayint = tempdisplayint;
+											display_has_sak = true;
+										}
+									}
+								}
+								else if (fi->fileName().tqcontains("kdmctl-")) {
+									tempdisplaystr = tempdisplaystr.replace("kdmctl-", "");
+									tempdisplayint = tempdisplaystr.toInt(&isint);
+									if (isint) {
+										if (tempdisplayint < newdisplayint) {
+											newdisplayint = tempdisplayint;
+											display_has_sak = false;
+										}
+									}
+								}
+								++it;
+							}
+							if (display_has_sak) {
+								if (writefile(TQString(KDM_CONTROL_FIFO_SAK_FILE).tqarg(newdisplayint), "CLOSE\n") < 0) {
+									// Uh oh, something failed...
+									printf("Unable to write to KDM control socket %s\n\r", (TQString(KDM_CONTROL_FIFO_SAK_FILE).tqarg(newdisplayint)).ascii()); fflush(stdout);
+									unlink((TQString(KDM_CONTROL_FIFO_SAK_FILE).tqarg(newdisplayint)).ascii());
+									writeerror = true;
+								}
+								else {
+									struct stat buffer;
+									int status = -1;
+									int timeout_counter = 0;
+									while ((status != 0) && (timeout_counter < 30)) {
+										status = stat((TQString(KDM_CONTROL_FIFO_FILE).tqarg(newdisplayint)).ascii(), &buffer);
+										timeout_counter++;
+										usleep(100000);
+									}
+								}
+							}
+							else {
+								// Make sure the control socket is writable
+								if (writefile(TQString(KDM_CONTROL_FIFO_FILE).tqarg(newdisplayint), "PING\n") < 0) {
+									// Uh oh, something failed...
+									printf("Unable to write to KDM control socket %s\n\r", (TQString(KDM_CONTROL_FIFO_FILE).tqarg(newdisplayint)).ascii()); fflush(stdout);
+									unlink((TQString(KDM_CONTROL_FIFO_FILE).tqarg(newdisplayint)).ascii());
+									writeerror = true;
+								}
+							}
+							if (newdisplayint == (MAXIMUM_VTS+1)) {
+								writeerror = true;
+								systemexec(TRINITY_BIN_PREFIX "kdmctl -g reserve");
+								usleep(1000000);
+							}
+							if (writeerror)
+								have_valid_display = false;
+							else
+								have_valid_display = true;
 						}
-					}
-					if (!resultbkp.contains(":")) {
-						newdisplay = exec("ls /var/run/xdmctl/ | grep 'xdmctl-:0'");
-						printf("[DEBUG 400.d] %s\n\r", newdisplay.ascii()); fflush(stdout);
-						if (newdisplay != "") {
-							usebasedisplay=1;
+						else
+						{
+							// Could not find any existing kdm sessions; start a new one
+							systemexec(TRINITY_BIN_PREFIX "kdmctl -g reserve");
 						}
 					}
 
-					printf("[DEBUG 400.e] Creating new session\n\r"); fflush(stdout);
-					if (usebasedisplay) {
-						printf("[DEBUG 400.e] Using base display\n\r"); fflush(stdout);
-					}
-					// Attempt login
-
-// 					// Find next sequential inactive display
-// 					// FIXME
-// 					// This assumes the original VT is on display 0 at all times,
-// 					// which is not always true
-// 					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;
-// 						}
-// 					}
-
-					// This external bash code does not assume that the original VT is on display 0 at all times,
-					// but it is a bit sloppy to have to call it from here.  FIXME
-					newdisplayint = systemexec("smartauth_displayfinder");
-
 					newdisplay = TQString(":%1").tqarg(newdisplayint);
-					printf("[DEBUG 400.f] The next display to start will be %s\n\r", newdisplay.ascii()); fflush(stdout);
+					printf("[DEBUG 400.f] Logging in on display %s\n\r", newdisplay.ascii()); fflush(stdout);
 
-					if (!usebasedisplay) {
-						systemexec(TRINITY_BIN_PREFIX "kdmctl -g reserve");
-					}
-					TQString kdmctl_command = TQString("login\t%1\tnow\t%2\t%3\n").tqarg(newdisplay).tqarg(smartcard_username).tqarg(smartcard_password);
-					FILE* kdmctlpipe = popen(TRINITY_BIN_PREFIX "kdmctl -g -", "w");
-					if (pipe) {
-						fputs(kdmctl_command.ascii(), kdmctlpipe);
-						fflush(kdmctlpipe);
-						pclose(kdmctlpipe);
+					// Construct login string
+					TQString logincommand = TQString("LOGIN\t%1\t%2\n").tqarg(smartcard_username).tqarg(smartcard_password);
+					if (writefile(TQString(KDM_CONTROL_FIFO_FILE).tqarg(newdisplayint), logincommand) < 0) {
+						// Uh oh, something failed...
+						printf("Unable to write to KDM control socket %s\n\r", (TQString(KDM_CONTROL_FIFO_FILE).tqarg(newdisplayint)).ascii()); fflush(stdout);
 					}
-					sleep(2);
-					systemexec((TQString(TRINITY_BIN_PREFIX "kdmctl -g activate %1").tqarg(newdisplay)).ascii());
+
 					udisplay=newdisplay;
 				}
 
-- 
cgit v1.2.3

