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 Signed-off-by: Harald Freudenberger --- a/usr/lib/pkcs11/common/utility.c +++ b/usr/lib/pkcs11/common/utility.c @@ -557,9 +557,11 @@ 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 @@ 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 @@ /* 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; } } --- 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 #include #include +#include +#include #include "log.h" #include "slotmgr.h" @@ -309,8 +311,13 @@ 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,14 +329,91 @@ 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); } 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); + } } /***************************************** @@ -341,205 +425,191 @@ *****************************************/ 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 + 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?) */ + + /* Do some basic sanity checks */ + run_sanity_checks(); + + /* 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); + fclose(stderr); + fclose(stdout); + fclose(stdin); #endif - - } - } - - - } else { - + } + } + } else { #ifdef DEV - // Log only on development builds - LogLog("Not becoming a daemon...\n"); + // Log only on development builds + LogLog("Not becoming a daemon...\n"); #endif - - } - - - /***************************************** - * - * 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; - } - - - - - /* ultimatly we will create a couple of threads which monitor the slot db - and handle the insertion and removal of tokens from the slot. - */ - - /* For Testing the Garbage collection routines */ - /* - shmp->proc_table[3].inuse = TRUE; - shmp->proc_table[3].proc_id = 24328; - */ + } + + /***************************************** + * + * 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; + } + + /* ultimatly we will create a couple of threads which monitor the slot db + and handle the insertion and removal of tokens from the slot. + */ + + /* For Testing the Garbage collection routines */ + /* + shmp->proc_table[3].inuse = TRUE; + shmp->proc_table[3].proc_id = 24328; + */ #if !defined(NOGARBAGE) -printf("Start garbage \n"); - /* start garbage collection thread */ - if ( ! StartGCThread(shmp) ) { - DetachSocketListener(socketfd); - DestroyMutexes(); - DetachFromSharedMemory(); - DestroySharedMemory(); - return 9; - } + 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); - } - } - - while (1) { + // 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); + } + } + + while (1) { #if !(THREADED) && !(NOGARBAGE) - CheckForGarbage(shmp); + 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. - * - *************************************************************/ - + 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 */