Blob Blame History Raw
commit 8962d298d98df0331d3870e2a490e1781a33a872
Author: Vineetha Pai <vpishar@us.ibm.com>
Date:   Fri Jun 3 16:34:54 2016 -0400

    1) Create lock and log directories from pkcsslotd when
    they are not available on the system.
    2) The patch also does basic sanity checks of asserting the presence
    of pkcs11 group, euid, gid of the process running pkcsslotd.
    3) The patch also checks if token directories are available on
    the system.
    4) The token lock sub-directories are created from opencryptoki while
    the token is configured via pkcsconf or when the first call to the token
    is made via C_Initialize.
    Signed-off-by: Vineetha Pai <vpishar@us.ibm.com>
    Signed-off-by: Harald Freudenberger <freude@linux.vnet.ibm.com>

diff --git a/usr/lib/pkcs11/common/utility.c b/usr/lib/pkcs11/common/utility.c
index 9f58849..3cbb8da 100755
--- a/usr/lib/pkcs11/common/utility.c
+++ b/usr/lib/pkcs11/common/utility.c
@@ -557,9 +557,11 @@ static int spinxplfd = -1;
 CK_RV CreateXProcLock(void)
 {
 	CK_BYTE lockfile[PATH_MAX];
+	CK_BYTE lockdir[PATH_MAX];
 	struct group *grp;
 	struct stat statbuf;
 	mode_t mode = (S_IRUSR | S_IRGRP);
+	int ret = -1;
 
 	if (spinxplfd == -1) {
 
@@ -571,9 +573,42 @@ CK_RV CreateXProcLock(void)
 				return CKR_FUNCTION_FAILED;
 		}
 
+		/** create lock subdir for each token if it doesn't exist.
+		  * The root directory should be created in slotmgr daemon **/
+		sprintf(lockdir, "%s/%s", LOCKDIR_PATH, SUB_DIR);
+
+		ret = stat(lockdir, &statbuf);
+		if (ret != 0 && errno == ENOENT) {
+			/* dir does not exist, try to create it */
+			ret  = mkdir(lockdir, S_IRWXU|S_IRWXG);
+			if (ret != 0) {
+				OCK_SYSLOG(LOG_ERR,
+						"Directory(%s) missing: %s\n",
+						lockdir,
+						strerror(errno));
+				goto err;
+			}
+			grp = getgrnam("pkcs11");
+			/* set ownership to euid, and pkcs11 group */
+			if (chown(lockdir, geteuid(), grp->gr_gid) != 0) {
+				fprintf(stderr, "Failed to set owner:group \
+						ownership\
+						on %s directory", lockdir);
+				goto err;
+			}
+			/* mkdir does not set group permission right, so
+			 ** trying explictly here again */
+			if (chmod(lockdir, S_IRWXU|S_IRWXG) != 0){
+				fprintf(stderr, "Failed to change \
+						permissions\
+						on %s directory", lockdir);
+				goto err;
+			}
+		}
+
 		/* create user lock file */
 		sprintf(lockfile, "%s/%s/LCK..%s",
-			LOCKDIR_PATH, SUB_DIR, SUB_DIR);
+				LOCKDIR_PATH, SUB_DIR, SUB_DIR);
 
 		if (stat(lockfile, &statbuf) == 0)
 			spinxplfd = open(lockfile, O_RDONLY, mode);
@@ -583,30 +618,30 @@ CK_RV CreateXProcLock(void)
 				/* umask may prevent correct mode,so set it. */
 				if (fchmod(spinxplfd, mode) == -1) {
 					OCK_SYSLOG(LOG_ERR, "fchmod(%s): %s\n",
-						   lockfile, strerror(errno));
+							lockfile, strerror(errno));
 					goto err;
 				}
 
 				grp = getgrnam("pkcs11");
 				if (grp != NULL) {
 					if (fchown(spinxplfd, -1, grp->gr_gid)
-					    == -1) {
+							== -1) {
 						OCK_SYSLOG(LOG_ERR,
-							   "fchown(%s): %s\n",
-							   lockfile,
-							   strerror(errno));
+								"fchown(%s): %s\n",
+								lockfile,
+								strerror(errno));
 						goto err;
 					}
 				} else {
 					OCK_SYSLOG(LOG_ERR, "getgrnam(): %s\n",
-						   strerror(errno));
+							strerror(errno));
 					goto err;
 				}
 			}
 		}
 		if (spinxplfd == -1) {
 			OCK_SYSLOG(LOG_ERR, "open(%s): %s\n",
-				   lockfile, strerror(errno));
+					lockfile, strerror(errno));
 			return CKR_FUNCTION_FAILED;
 		}
 	}
diff --git a/usr/sbin/pkcsslotd/slotmgr.c b/usr/sbin/pkcsslotd/slotmgr.c
index 8a2f521..e28fadb 100755
--- a/usr/sbin/pkcsslotd/slotmgr.c
+++ b/usr/sbin/pkcsslotd/slotmgr.c
@@ -8,10 +8,10 @@
 
              1. DEFINITIONS
 
-             "Contribution" means: 
+             "Contribution" means:
                    a) in the case of the initial Contributor, the
                    initial code and documentation distributed under
-                   this Agreement, and 
+                   this Agreement, and
 
                    b) in the case of each subsequent Contributor:
                    i) changes to the Program, and
@@ -35,7 +35,7 @@
              "Licensed Patents " mean patent claims licensable by a
              Contributor which are necessarily infringed by the use or
              sale of its Contribution alone or when combined with the
-             Program. 
+             Program.
 
              "Program" means the Contributions distributed in
              accordance with this Agreement.
@@ -130,7 +130,7 @@
                    a) it must be made available under this Agreement;
                    and
                    b) a copy of this Agreement must be included with
-                   each copy of the Program. 
+                   each copy of the Program.
 
              Contributors may not remove or alter any copyright notices
              contained within the Program.
@@ -138,7 +138,7 @@
              Each Contributor must identify itself as the originator of
              its Contribution, if any, in a manner that reasonably
              allows subsequent Recipients to identify the originator of
-             the Contribution. 
+             the Contribution.
 
 
              4. COMMERCIAL DISTRIBUTION
@@ -199,7 +199,7 @@
              Agreement, including but not limited to the risks and
              costs of program errors, compliance with applicable laws,
              damage to or loss of data, programs or equipment, and
-             unavailability or interruption of operations. 
+             unavailability or interruption of operations.
 
              6. DISCLAIMER OF LIABILITY
              EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER
@@ -248,7 +248,7 @@
              use and distribution of the Program as soon as reasonably
              practicable. However, Recipient's obligations under this
              Agreement and any licenses granted by Recipient relating
-             to the Program shall continue and survive. 
+             to the Program shall continue and survive.
 
              Everyone is permitted to copy and distribute copies of
              this Agreement, but in order to avoid inconsistency the
@@ -280,7 +280,7 @@
              States of America. No party to this Agreement will bring a
              legal action under this Agreement more than one year after
              the cause of action arose. Each party waives its rights to
-             a jury trial in any resulting litigation. 
+             a jury trial in any resulting litigation.
 
 
 
@@ -294,6 +294,8 @@
 #include <unistd.h>
 #include <errno.h>
 #include <sys/types.h>
+#include <sys/stat.h>
+#include <grp.h>
 
 #include "log.h"
 #include "slotmgr.h"
@@ -309,8 +311,13 @@ unsigned char NumberSlotsInDB = 0;
 int socketfd;
 Slot_Mgr_Socket_t      socketData;
 
-/* 
-   We make main() able to modify Daemon so that we can 
+struct dircheckinfo_s {
+	const char *dir;
+	int mode;
+};
+
+/*
+   We make main() able to modify Daemon so that we can
    daemonize or not based on a command-line argument
  */
 extern BOOL               Daemon;
@@ -322,9 +329,9 @@ DumpSharedMemory(void)
 	u_int32 *p;
 	char Buf[PATH_MAX];
 	u_int32 i;
-    
+
 	p = (u_int32 *) shmp;
-    
+
 	for ( i = 0; i < 15; i++ ) {
 		sprintf(Buf, "%08X %08X %08X %08X", p[0+(i*4)], p[1+(i*4)], p[2+(i*4)], p[3+(i*4)]);
 		LogLog(Buf);
@@ -332,6 +339,83 @@ DumpSharedMemory(void)
 	return;
 }
 
+/** This function does basic sanity checks to make sure the
+ *  eco system is in place for opencryptoki to run properly.
+ **/
+void run_sanity_checks()
+{
+	int i, ec, uid = -1;
+	struct group *grp = NULL;
+	struct stat sbuf;
+	struct dircheckinfo_s dircheck[] = {
+		//drwxrwx---
+		{LOCKDIR_PATH, S_IRWXU|S_IRWXG},
+		{OCK_LOGDIR, S_IRWXU|S_IRWXG},
+		{NULL, 0},
+	};
+
+	/* first check that our effective user id is root */
+	uid = (int) geteuid();
+	if (uid != 0) {
+		fprintf(stderr, "This daemon needs root privilegies, but the effective user id is not 'root'.\n");
+		exit(1);
+	}
+
+	/* check that the pkcs11 group exists */
+	grp = getgrnam("pkcs11");
+	if (!grp) {
+		fprintf(stderr, "There is no 'pkcs11' group on this system.\n");
+		exit(1);
+	}
+
+	/* check effective group id */
+	uid = (int) getegid();
+	if (uid != 0 && uid != (int) grp->gr_gid) {
+		fprintf(stderr, "This daemon should have an effective group id of 'root' or 'pkcs11'.\n");
+		exit(1);
+	}
+
+	/* Create base lock and log directory here. API..Lock file is
+	 * accessed from the daemon in CreateXProcLock() in mutex.c.*/
+	for (i=0; dircheck[i].dir != NULL; i++) {
+		ec = stat(dircheck[i].dir, &sbuf);
+		if (ec != 0 && errno == ENOENT) {
+			/* dir does not exist, try to create it */
+			ec = mkdir(dircheck[i].dir, dircheck[i].mode);
+			if (ec != 0) {
+				fprintf(stderr, "Directory %s missing\n",
+						dircheck[i].dir);
+				exit(2);
+			}
+			/* set ownership to root, and pkcs11 group */
+			if (chown(dircheck[i].dir, geteuid(), grp->gr_gid) != 0) {
+				fprintf(stderr, "Failed to set owner:group \
+						ownership\
+						on %s directory", dircheck[i].dir);
+				exit(1);
+			}
+			/* mkdir does not set group permission right, so
+			 * trying explictly here again */
+			if (chmod(dircheck[i].dir, dircheck[i].mode) != 0){
+				fprintf(stderr, "Failed to change \
+						permissions\
+						on %s directory", dircheck[i].dir);
+				exit(1);
+			}
+		}
+	}
+
+	/** check if token directory is available, if not flag an error.
+	 *  We do not create token directories here as admin should
+	 *  configure and decide which tokens to expose to opencryptoki
+	 *  outside of opencryptoki and pkcsslotd */
+	ec = stat(CONFIG_PATH, &sbuf);
+	if (ec != 0 && errno == ENOENT) {
+		fprintf(stderr, "Token directories missing\n");
+		exit(2);
+	}
+}
+
 /*****************************************
  *  main() -
  *      You know what main does.
@@ -341,205 +425,191 @@ DumpSharedMemory(void)
  *****************************************/
 
 int main ( int argc, char *argv[], char *envp[]) {
-   int ret;
-
-   /**********************************/
-   /* Read in command-line arguments */
-   /**********************************/
-
-   /* FIXME: Argument for daemonizing or not */
-   /* FIXME: Argument for debug level */
-   /* FIXME: Arguments affecting the log files, whether to use syslog, etc. (Read conf file?) */
-
-
-   /* Report our debug level */
-   if ( GetDebugLevel() > DEBUG_NONE) {
-
-     DbgLog(GetDebugLevel(), "Starting with debugging messages logged at level %d (%d = No messages; %d = few; %d = more, etc.)", 
-	    GetDebugLevel(), DEBUG_NONE, DEBUG_LEVEL0, DEBUG_LEVEL1);
-
-   }
-
-
-   /* Save our startup directory */
-   SaveStartupDirectory( argv[0]  );
-
-   ret = load_and_parse(OCK_CONFIG);
-   if (ret != 0) {
-      ErrLog("Failed to read config file.\n");
-      return 1;
-   } else
-      DbgLog (DL0, "Parse config file succeeded.\n");
-
-   /* Allocate and Attach the shared memory region */
-   if ( ! CreateSharedMemory() ) {
-     /* CreateSharedMemory() does it's own error logging */
-     return 1;
-   }
-
-   DbgLog(DL0,"SHMID %d  token %#X \n", shmid, tok);
-
-   /* Now that we've created the shared memory segment, we attach to it */
-   if ( ! AttachToSharedMemory() ) {
-     /* AttachToSharedMemory() does it's own error logging */
-     DestroySharedMemory();
-     return 2;
-   }
-
-   /* Initialize the global shared memory mutex (and the attribute used to create the per-process mutexes */
-   if ( ! InitializeMutexes() ) {
-     DetachFromSharedMemory();
-     DestroySharedMemory();
-     return 3;
-   }
-
-   /* Get the global shared memory mutex */
-
-   XProcLock();
-
-   /* Populate the Shared Memory Region */
-   if ( ! InitSharedMemory(shmp) ) {
-
-      XProcUnLock();
-
-     DetachFromSharedMemory();
-     DestroySharedMemory();
-     return 4;
-   }
-   
-   /* Release the global shared memory mutex */
-   XProcUnLock();
-
-   if ((socketfd = CreateListenerSocket()) < 0) {
-      DestroyMutexes();
-      DetachFromSharedMemory();
-      DestroySharedMemory();
-      return 5;
-   }
-
-   if (!InitSocketData(&socketData)) {
-      DetachSocketListener(socketfd);
-      DestroyMutexes();
-      DetachFromSharedMemory();
-      DestroySharedMemory();
-      return 6;
-   }
-
-   /*
-    *  Become a Daemon, if called for
-    */
-   if ( Daemon ) {
-        pid_t  pid;
-        if ( (pid = fork()) < 0 ){
-          DetachSocketListener(socketfd);
-          DestroyMutexes();
-          DetachFromSharedMemory();
-          DestroySharedMemory();
-          return 7;
-        } else {
-           if ( pid != 0) {
-              exit(0); // Terminate the parent
-           } else {
-
-              setsid(); // Session leader
-#ifndef DEV
-              fclose(stderr);
-              fclose(stdout);
-              fclose(stdin);
-#endif
+	int ret;
 
-           }
-        }
+	/**********************************/
+	/* Read in command-line arguments */
+	/**********************************/
 
+	/* FIXME: Argument for daemonizing or not */
+	/* FIXME: Argument for debug level */
+	/* FIXME: Arguments affecting the log files, whether to use syslog, etc. (Read conf file?) */
 
-   } else {
+	/* Do some basic sanity checks */
+	run_sanity_checks();
 
-#ifdef DEV
-     // Log only on development builds
-     LogLog("Not becoming a daemon...\n");
-#endif
+	/* Report our debug level */
+	if ( GetDebugLevel() > DEBUG_NONE) {
+		DbgLog(GetDebugLevel(), "Starting with debugging messages logged at \
+				level %d (%d = No messages; %d = few; %d = more, etc.)",
+				GetDebugLevel(), DEBUG_NONE, DEBUG_LEVEL0, DEBUG_LEVEL1);
+	}
+
+	/* Save our startup directory */
+	SaveStartupDirectory( argv[0]  );
+
+	ret = load_and_parse(OCK_CONFIG);
+	if (ret != 0) {
+		ErrLog("Failed to read config file.\n");
+		return 1;
+	} else
+		DbgLog (DL0, "Parse config file succeeded.\n");
 
-   }
+	/* Allocate and Attach the shared memory region */
+	if ( ! CreateSharedMemory() ) {
+		/* CreateSharedMemory() does it's own error logging */
+		return 1;
+	}
 
-   
-   /*****************************************
-    * 
-    * Register Signal Handlers
-    * Daemon probably should ignore ALL signals possible, since termination
-    * while active is a bad thing...  however one could check for 
-    * any processes active in the shared memory, and destroy the shm if
-    * the process wishes to terminate.
-    * 
-    *****************************************/
+	DbgLog(DL0,"SHMID %d  token %#X \n", shmid, tok);
 
-   /*   
-    *   We have to set up the signal handlers after we daemonize because
-    *   the daemonization process redefines our handler for (at least) SIGTERM
-    */
+	/* Now that we've created the shared memory segment, we attach to it */
+	if ( ! AttachToSharedMemory() ) {
+		/* AttachToSharedMemory() does it's own error logging */
+		DestroySharedMemory();
+		return 2;
+	}
 
-   if ( ! SetupSignalHandlers() ) {
-     DetachSocketListener(socketfd);
-     DestroyMutexes();
-     DetachFromSharedMemory();
-     DestroySharedMemory();
-     return 8;
-   }
+	/* Initialize the global shared memory mutex (and the attribute
+	* used to create the per-process mutexes */
+	if ( ! InitializeMutexes() ) {
+		DetachFromSharedMemory();
+		DestroySharedMemory();
+		return 3;
+	}
 
+	/* Get the global shared memory mutex */
+	XProcLock();
 
+	/* Populate the Shared Memory Region */
+	if ( ! InitSharedMemory(shmp) ) {
 
+		XProcUnLock();
 
-   /*  ultimatly we will create a couple of threads which monitor the slot db
-       and handle the insertion and removal of tokens from the slot.
-    */
+		DetachFromSharedMemory();
+		DestroySharedMemory();
+		return 4;
+	}
 
-   /* For Testing the Garbage collection routines */
-   /*
-      shmp->proc_table[3].inuse = TRUE;
-      shmp->proc_table[3].proc_id = 24328;
-      */
+	/* Release the global shared memory mutex */
+	XProcUnLock();
 
-#if !defined(NOGARBAGE)
-printf("Start garbage \n");
-   /* start garbage collection thread */
-   if ( ! StartGCThread(shmp) ) {
-     DetachSocketListener(socketfd);
-     DestroyMutexes();
-     DetachFromSharedMemory();
-     DestroySharedMemory();
-     return 9;
-   }
+	if ((socketfd = CreateListenerSocket()) < 0) {
+		DestroyMutexes();
+		DetachFromSharedMemory();
+		DestroySharedMemory();
+		return 5;
+	}
+
+	if (!InitSocketData(&socketData)) {
+		DetachSocketListener(socketfd);
+		DestroyMutexes();
+		DetachFromSharedMemory();
+		DestroySharedMemory();
+		return 6;
+	}
+
+	/*
+	 *  Become a Daemon, if called for
+	 */
+	if ( Daemon ) {
+		pid_t  pid;
+		if ( (pid = fork()) < 0 ){
+			DetachSocketListener(socketfd);
+			DestroyMutexes();
+			DetachFromSharedMemory();
+			DestroySharedMemory();
+			return 7;
+		} else {
+			if ( pid != 0) {
+				exit(0); // Terminate the parent
+			} else {
+
+				setsid(); // Session leader
+#ifndef DEV
+				fclose(stderr);
+				fclose(stdout);
+				fclose(stdin);
+#endif
+			}
+		}
+	} else {
+#ifdef DEV
+		// Log only on development builds
+		LogLog("Not becoming a daemon...\n");
 #endif
+	}
 
-     // We've fully become a daemon.  Now create the PID file
-     {
-        FILE *pidfile;
+	/*****************************************
+	 *
+	 * Register Signal Handlers
+	 * Daemon probably should ignore ALL signals possible, since termination
+	 * while active is a bad thing...  however one could check for
+	 * any processes active in the shared memory, and destroy the shm if
+	 * the process wishes to terminate.
+	 *
+	 *****************************************/
+
+	/*
+	 *   We have to set up the signal handlers after we daemonize because
+	 *   the daemonization process redefines our handler for (at least) SIGTERM
+	 */
+	if ( ! SetupSignalHandlers() ) {
+		DetachSocketListener(socketfd);
+		DestroyMutexes();
+		DetachFromSharedMemory();
+		DestroySharedMemory();
+		return 8;
+	}
 
-        pidfile = fopen(PID_FILE_PATH,"w");
-        if (pidfile) {
-           fprintf(pidfile,"%d",getpid());
-	   fclose(pidfile);
-        }
-     }
+	/*  ultimatly we will create a couple of threads which monitor the slot db
+	    and handle the insertion and removal of tokens from the slot.
+	    */
 
-   while (1) {
-#if !(THREADED) && !(NOGARBAGE)
-     CheckForGarbage(shmp);
-#endif
+	/* For Testing the Garbage collection routines */
+	/*
+	   shmp->proc_table[3].inuse = TRUE;
+	   shmp->proc_table[3].proc_id = 24328;
+	   */
 
-     SocketConnectionHandler(socketfd, 10);
+#if !defined(NOGARBAGE)
+	printf("Start garbage \n");
+	/* start garbage collection thread */
+	if ( ! StartGCThread(shmp) ) {
+		DetachSocketListener(socketfd);
+		DestroyMutexes();
+		DetachFromSharedMemory();
+		DestroySharedMemory();
+		return 9;
+	}
+#endif
 
-   }
+	// We've fully become a daemon.  Now create the PID file
+	{
+		FILE *pidfile;
 
+		pidfile = fopen(PID_FILE_PATH,"w");
+		if (pidfile) {
+			fprintf(pidfile,"%d",getpid());
+			fclose(pidfile);
+		}
+	}
 
-   /*************************************************************
-    * 
-    *  Here we need to actualy go through the processes and verify that thye
-    *  still exist.  If not, then they terminated with out properly calling
-    *  C_Finalize and therefore need to be removed from the system.
-    *  Look for a system routine to determine if the shared memory is held by 
-    *  the process to further verify that the proper processes are in the 
-    *  table.
-    * 
-    *************************************************************/
+	while (1) {
+#if !(THREADED) && !(NOGARBAGE)
+		CheckForGarbage(shmp);
+#endif
+		SocketConnectionHandler(socketfd, 10);
+	}
 
+	/*************************************************************
+	 *
+	 *  Here we need to actualy go through the processes and verify that thye
+	 *  still exist.  If not, then they terminated with out properly calling
+	 *  C_Finalize and therefore need to be removed from the system.
+	 *  Look for a system routine to determine if the shared memory is held by
+	 *  the process to further verify that the proper processes are in the
+	 *  table.
+	 *
+	 *************************************************************/
 } /* end main */