#define kCCacheLockFileDirPrefix "/tmp/.KerberosLogin-"
#define kCCacheLockFileSuffix "/KLLCCache.lock"
#define kLockFileDirPerms (S_IRUSR | S_IWUSR | S_IXUSR)
#define kLockFilePerms (S_IRUSR | S_IWUSR)
static KLStatus __KLGetLockFile (char **outLockFileDirectory, char **outLockFile, uid_t *outUID);
static KLStatus __KLCheckLockFileDirectory (char *lockFileDirectory, uid_t lockFileUID);
static pthread_mutex_t gLockFileMutex = PTHREAD_MUTEX_INITIALIZER;
static KLLockType gLockType = kNoLock;
static KLIndex gLockRefCount = 0;
static int gLockFileFD = -1;
#pragma mark -
KLStatus __KLLockCCache (KLLockType inLockType)
{
if (__KLIsKerberosAgent()) { return klNoErr; }
KLStatus lockErr = pthread_mutex_lock (&gLockFileMutex);
KLStatus err = lockErr;
if ((inLockType != kReadLock) && (inLockType != kWriteLock)) {
err = KLError_ (klParameterErr);
}
if (err == klNoErr) {
if (gLockRefCount == 0) {
char *lockFileName = NULL;
char *lockFileDirectoryName = NULL;
uid_t lockFileUID;
if (err == klNoErr) {
err = __KLGetLockFile (&lockFileDirectoryName, &lockFileName, &lockFileUID);
}
if (err == klNoErr) {
if (mkdir (lockFileDirectoryName, kLockFileDirPerms) != 0) {
if (errno != EEXIST) { err = KLError_ (errno); }
}
}
if (err == klNoErr) {
err = __KLCheckLockFileDirectory (lockFileDirectoryName, lockFileUID);
}
if (err == klNoErr) {
gLockFileFD = open (lockFileName, O_CREAT, kLockFilePerms);
if (gLockFileFD < 0) { err = KLError_ (errno); }
}
if (lockFileName != NULL) { KLDisposeString (lockFileName); }
if (lockFileDirectoryName != NULL) { KLDisposeString (lockFileDirectoryName); }
}
}
if (err == klNoErr) {
if ((gLockRefCount == 0) || ((inLockType == kWriteLock) && (gLockType == kReadLock))) { for (;;) {
if (flock (gLockFileFD, ((inLockType == kWriteLock) ? LOCK_EX : LOCK_SH) | LOCK_NB) == 0) {
gLockType = inLockType;
break;
} else {
if (errno == EWOULDBLOCK) {
__KLCallIdleCallback ();
usleep (10);
continue;
} else {
if (gLockRefCount == 0) {
close (gLockFileFD);
gLockFileFD = -1;
}
err = KLError_ (errno);
break;
}
}
}
}
}
if (err == klNoErr) {
gLockRefCount++;
}
if (lockErr == klNoErr) { pthread_mutex_unlock (&gLockFileMutex); }
return KLError_ (err);
}
KLStatus __KLUnlockCCache (void)
{
if (__KLIsKerberosAgent()) { return klNoErr; }
KLStatus lockErr = pthread_mutex_lock (&gLockFileMutex);
KLStatus err = lockErr;
if (gLockRefCount < 1) { err = KLError_ (klParameterErr); }
if (gLockFileFD < 0) { err = KLError_ (klParameterErr); }
if (err == klNoErr) {
if ((gLockRefCount == 1) && (gLockFileFD >= 0)) {
err = flock (gLockFileFD, LOCK_UN);
if (err == klNoErr) {
close (gLockFileFD);
gLockFileFD = -1;
gLockType = kNoLock;
}
}
}
if (err == klNoErr) {
gLockRefCount--;
}
if (lockErr == klNoErr) { pthread_mutex_unlock (&gLockFileMutex); }
return KLError_ (err);
}
#pragma mark -
static KLStatus __KLGetLockFile (char **outLockFileDirectory, char **outLockFile, uid_t *outUID)
{
KLStatus err = klNoErr;
uid_t uid = 0;
char uidString[64];
char *fileName = NULL;
char *directoryName = NULL;
if (outLockFileDirectory == NULL) { err = KLError_ (klParameterErr); }
if (outLockFile == NULL) { err = KLError_ (klParameterErr); }
if (outUID == NULL) { err = KLError_ (klParameterErr); }
if (err == klNoErr) {
uid = geteuid ();
}
if (err == klNoErr) {
int count = snprintf (uidString, sizeof (uidString), "%d", uid);
if (count > sizeof (uidString)) {
dprintf ("__KLGetLockFile: WARNING! UID %d needs %ld bytes and buffer is %ld bytes",
uid, count, sizeof (uidString));
err = KLError_ (klParameterErr);
}
}
if (err == klNoErr) {
err = __KLCreateString (kCCacheLockFileDirPrefix, &directoryName);
}
if (err == klNoErr) {
err = __KLAppendToString (uidString, &directoryName);
}
if (err == klNoErr) {
err = __KLAppendToString ("-", &directoryName);
}
if (err == klNoErr) {
err = __KLAppendToString (LoginSessionGetSecuritySessionName (), &directoryName);
}
if (err == klNoErr) {
err = __KLCreateString (directoryName, &fileName);
}
if (err == klNoErr) {
err = __KLAppendToString (kCCacheLockFileSuffix, &fileName);
}
if (err == klNoErr) {
*outUID = geteuid ();
*outLockFile = fileName;
*outLockFileDirectory = directoryName;
} else {
if (fileName != NULL) { KLDisposeString (fileName); }
if (directoryName != NULL) { KLDisposeString (directoryName); }
}
return KLError_ (err);
}
static KLStatus __KLCheckLockFileDirectory (char *lockFileDirectory, uid_t lockFileUID)
{
KLStatus err = klNoErr;
struct stat sb;
if (err == klNoErr) {
err = stat (lockFileDirectory, &sb);
if (err != 0) {
dprintf ("__KLCheckLockFileDirectory(): stat(%s) returned %ld (%s)\n",
lockFileDirectory, errno, strerror (errno));
err = KLError_ (errno);
}
}
if (err == klNoErr) {
if (!S_ISDIR (sb.st_mode)) {
dprintf ("__KLCheckLockFileDirectory(): %s is not a directory\n", lockFileDirectory);
err = KLError_ (ENOTDIR);
}
}
if (err == klNoErr) {
if (sb.st_uid != lockFileUID) {
dprintf ("__KLCheckLockFileDirectory(): %s is owned by uid %ld, not uid %ld\n",
lockFileDirectory, sb.st_uid, lockFileUID);
}
}
if (err == klNoErr) {
if ((sb.st_mode & ALLPERMS) != kLockFileDirPerms) {
if (chmod (lockFileDirectory, kLockFileDirPerms) != 0) {
err = KLError_ (errno);
dprintf ("__KLCheckLockFileDirectory(): %s has permission bits 0x%lx, not 0x%lx\n",
lockFileDirectory, (sb.st_mode & ALLPERMS), kLockFileDirPerms);
}
}
}
return KLError_ (err);
}