CKerberosPrincipal.cpp [plain text]
#include "CKerberosPrincipal.h"
#include "KerberosInterface.h"
#include "PSUtilitiesDefs.h"
#include <syslog.h>
#include <unistd.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <fcntl.h>
#define FILE_HEADER "kdb5_util load_dump version 5\n"
PWSFKerberosPrincipalList::PWSFKerberosPrincipalList()
: mBuffer(NULL), mPrincipalList(0), mPrincipalArray(0), mPrincipalArrayCount(0)
{
}
PWSFKerberosPrincipalList::~PWSFKerberosPrincipalList()
{
while (mPrincipalList != NULL)
delete mPrincipalList;
if (mBuffer != NULL)
delete mBuffer;
if ( mPrincipalArray != NULL )
free( mPrincipalArray );
}
int PWSFKerberosPrincipalList::ReadAllPrincipalsFromDB(time_t inAfterThisModDate, long inMaxPrincipals)
{
PWSFKerberosPrincipal* current;
char* ptr;
char* args[5];
int result;
long princCount = 0;
struct stat sb;
int dumpLen = 0;
char tempFileName[50];
int fd;
strcpy(tempFileName, "/var/db/krb5kdc/KerbDumpFileXXXXX");
mktemp(tempFileName);
args[0] = "kdb5_util";
args[1] = "dump";
args[2] = tempFileName;
args[3] = NULL;
result = pwsf_LaunchTaskWithIO(kKDBUtilLocalFilePath, args, NULL, NULL, 0, NULL);
result = lstat( tempFileName, &sb );
if ( result == 0 )
dumpLen = sb.st_size;
if ( (result != 0) || (dumpLen <= (long)sizeof(FILE_HEADER)) )
{
unlink(tempFileName);
return -1;
}
mBuffer = (char*)malloc(dumpLen + 1);
if ( mBuffer == NULL ) {
return -1;
}
fd = open(tempFileName, O_RDONLY);
if ( fd == -1 ) {
free( mBuffer );
mBuffer = NULL;
return -1;
}
result = read(fd, mBuffer, dumpLen);
close(fd);
unlink(tempFileName);
strcat(tempFileName, ".dump_ok");
unlink(tempFileName);
if (result != dumpLen)
return -1;
mBuffer[dumpLen] = 0;
ptr = mBuffer;
current = new PWSFKerberosPrincipal(ptr, this);
ptr = current->ParseBuffer(true);
while (*ptr != 0)
{
current = new PWSFKerberosPrincipal(ptr, this);
ptr = current->ParseBuffer(false);
if (!current->IsPolicy() && (current->GetRecordModDate() < inAfterThisModDate))
delete current;
else
princCount++;
if ( inMaxPrincipals > 0 && princCount >= inMaxPrincipals )
break;
}
mPrincipalArray = (PWSFKerberosPrincipal **) calloc( princCount + 1, sizeof(PWSFKerberosPrincipal *) );
if ( mPrincipalArray != NULL )
{
int32_t index = 0;
for ( current = mPrincipalList; current != NULL && index < princCount; current = current->GetNext() )
mPrincipalArray[index++] = current;
mPrincipalArrayCount = princCount;
}
return 0;
}
int PWSFKerberosPrincipalList::WriteAllPrincipalsToDB()
{
PWSFKerberosPrincipal* current = mPrincipalList;
char tempFileName[50];
int status;
if (mPrincipalList == NULL)
return 0;
strcpy(tempFileName, "/var/db/krb5kdc/KerbLoadFileXXXXX");
int fd = mkstemp(tempFileName);
write(fd, FILE_HEADER, sizeof(FILE_HEADER) - 1);
int count = 0;
while (current != NULL)
{
current->WritePrincipalToTempFile(fd);
count++;
current = current->GetNext();
}
close(fd);
char* args[5];
args[0] = "kdb5_util";
args[1] = "load";
args[2] = "-update";
args[3] = tempFileName;
args[4] = NULL;
status = pwsf_LaunchTaskWithIO(kKDBUtilLocalFilePath, args, NULL, NULL, 0, NULL);
unlink(tempFileName);
return status;
}
PWSFKerberosPrincipal* PWSFKerberosPrincipalList::GetPrincipalByName(char* principalName)
{
PWSFKerberosPrincipal* current = mPrincipalList;
char *name = NULL;
char firstChar;
long index = 0;
long upper = 0;
long lower = 0;
long delta = 0;
int deltaHitZero = 0;
int compare = 0;
if (principalName == NULL || *principalName == '\0')
return NULL;
firstChar = *principalName;
if ( mPrincipalArray != NULL )
{
lower = 0;
upper = mPrincipalArrayCount - 1;
index = ((upper - lower) / 2);
do
{
current = mPrincipalArray[index];
if ( current != NULL )
name = current->GetName();
if ( name != NULL )
{
compare = strcmp( name, principalName );
if ( compare == 0 )
return current;
else
if ( compare < 0 ) {
upper = index;
delta = ((upper - lower) / 2);
index -= MAX(delta, 1);
}
else
if ( compare > 0 ) {
lower = index;
delta = ((upper - lower) / 2);
index += MAX(delta, 1);
}
if ( delta == 0 )
{
if ( deltaHitZero )
return NULL;
else
deltaHitZero = 1;
}
}
}
while ( index >= 0 && index < mPrincipalArrayCount );
return NULL;
}
else
{
while (current != NULL)
{
name = current->GetName();
if (name != NULL && *name == firstChar && strcmp(name + 1, principalName + 1) == 0)
break;
current = current->GetNext();
}
}
return current;
}
PWSFKerberosPrincipal* PWSFKerberosPrincipalList::GetPrincipalByIndex(int index)
{
int i;
PWSFKerberosPrincipal* current = mPrincipalList;
for (i = 0; (i < index) && (current != NULL); i++)
current = current->GetNext();
return current;
}
PWSFKerberosPrincipal* PWSFKerberosPrincipalList::ReadPrincipalFromFile(FILE* file, int recordSize)
{
return PWSFKerberosPrincipal::ReadPrincipalFromFile(file, recordSize, this);
}
PWSFKerberosPrincipal* PWSFKerberosPrincipalList::ReadPrincipalFromData(unsigned char *record, int recordSize)
{
return PWSFKerberosPrincipal::ReadPrincipalFromData(record, recordSize, this);
}
PWSFKerberosPrincipal::PWSFKerberosPrincipal()
: mBuffer(NULL), mOtherBuffer(NULL), mOwnsBuffer(true), mBufSize(0), mListOwner(NULL), mNext(NULL), mPrevious(NULL)
{
bzero( mEntries, sizeof(mEntries) );
}
PWSFKerberosPrincipal::PWSFKerberosPrincipal(char* buffer, PWSFKerberosPrincipalList* owner)
: mBuffer(buffer), mOtherBuffer(NULL), mOwnsBuffer(false), mBufSize(0), mListOwner(owner), mNext(NULL), mPrevious(NULL)
{
bzero( mEntries, sizeof(mEntries) );
mNext = owner->GetPrincipalByIndex(0);
if (mNext != NULL)
mNext->mPrevious = this;
owner->SetFirst(this);
}
PWSFKerberosPrincipal::PWSFKerberosPrincipal(PWSFKerberosPrincipalList* owner)
: mBuffer(NULL), mOtherBuffer(NULL), mOwnsBuffer(true), mBufSize(0), mListOwner(owner), mNext(NULL), mPrevious(NULL)
{
bzero( mEntries, sizeof(mEntries) );
mNext = owner->GetPrincipalByIndex(0);
if (mNext != NULL)
mNext->mPrevious = this;
owner->SetFirst(this);
}
PWSFKerberosPrincipal::~PWSFKerberosPrincipal()
{
if (mBuffer != NULL && mOwnsBuffer)
delete mBuffer;
if (mListOwner != NULL)
{
if (mNext != NULL)
mNext->mPrevious = mPrevious;
if (mPrevious == NULL)
mListOwner->SetFirst(mNext);
else
mPrevious->mNext = mNext;
}
if ( mOtherBuffer != NULL )
{
free( mOtherBuffer );
mOtherBuffer = NULL;
}
}
bool PWSFKerberosPrincipal::IsPolicy()
{
char *entryZero;
if ( (entryZero = mEntries[0]) == NULL )
return false;
return ( (*((unsigned long *)entryZero) == 'poli') &&
(strcmp(entryZero, "policy") == 0) );
}
char* PWSFKerberosPrincipal::GetName()
{
if (IsPolicy())
return mEntries[1];
else
return mEntries[6];
}
void PWSFKerberosPrincipal::CopyLastLogin(PWSFKerberosPrincipal* otherRecord)
{
mEntries[12] = GetEntryCopy(otherRecord, 12);
}
int PWSFKerberosPrincipal::GetFirstKeyEntryIndex()
{
if (IsPolicy())
return -1;
if ( mEntries[3] == NULL )
return -1;
int numTags = strtol(mEntries[3], NULL, 16);
int theIndex = 15 + (3 * numTags);
if ( theIndex > kKerberosPrincipalMaxEntries )
theIndex = -1;
return theIndex;
}
int PWSFKerberosPrincipal::GetPasswordModDateEntryIndex()
{
if (IsPolicy())
return -1;
if ( mEntries[3] == NULL )
return -1;
int numTags = strtol(mEntries[3], NULL, 16);
if ( 15 + (3 * (numTags-1)) > kKerberosPrincipalMaxEntries )
return -1;
for (int i = 0; i < numTags; i++)
{
if (mEntries[15 + (3 * i)] == NULL)
return -1;
if (strtol(mEntries[15 + (3 * i)], NULL, 16) == 1)
return (15 + (3 * i) + 2);
}
return -1;
}
time_t PWSFKerberosPrincipal::GetRecordModDate()
{
if (IsPolicy())
return 0;
if ( mEntries[3] == NULL )
return 0;
int numTags = strtol(mEntries[3], NULL, 16);
int i;
int index = 0;
time_t modDate = 0;
if ( 15 + (3 * (numTags-1)) > kKerberosPrincipalMaxEntries )
return 0;
for (i = 0; i < numTags; i++)
{
if (mEntries[15 + (3 * i)] == NULL)
return 0;
if (strtol(mEntries[15 + (3 * i)], NULL, 16) == 2)
{
index = (15 + (3 * i) + 2);
break;
}
}
if (index != 0)
{
char* modDateString = mEntries[index];
for (i = 6; i >= 0; i-=2)
{
int hiNibble = (modDateString[i] >= 'a') ? modDateString[i] - 'a' + 10 : modDateString[i] - '0';
int loNibble = (modDateString[i+1] >= 'a') ? modDateString[i+1] - 'a' + 10 : modDateString[i+1] - '0';
modDate = (modDate << 8) + (hiNibble << 4) + loNibble;
}
}
return modDate;
}
void PWSFKerberosPrincipal::CopyPassword(PWSFKerberosPrincipal* otherRecord)
{
int modDateIndex = GetPasswordModDateEntryIndex();
int otherModDateIndex = otherRecord->GetPasswordModDateEntryIndex();
if ((modDateIndex != -1) && (otherModDateIndex != -1))
mEntries[modDateIndex] = GetEntryCopy(otherRecord, otherModDateIndex);
int index = GetFirstKeyEntryIndex();
int otherIndex = otherRecord->GetFirstKeyEntryIndex();
if ( index != -1 && otherIndex != -1 )
{
do
{
mEntries[index++] = GetEntryCopy(otherRecord, otherIndex);
} while (otherRecord->mEntries[otherIndex++] != NULL);
}
mEntries[4] = GetEntryCopy(otherRecord, 4);
}
char* PWSFKerberosPrincipal::ParseBuffer(bool skipLine)
{
char* cur = mBuffer;
int curEntry;
if ( mBuffer == NULL )
return NULL;
if (skipLine)
{
while (*cur != '\n') {
if (*cur == '\0')
return NULL;
cur++;
}
cur++;
}
mEntries[0] = cur;
curEntry = 1;
while (*cur != '\n' && *cur != '\0')
{
if (*cur == '\t')
{
*cur = '\0';
cur++;
mEntries[curEntry++] = cur;
}
cur++;
}
mEntries[curEntry] = NULL;
if (*cur == '\0')
return cur;
*cur = '\0';
if (mBufSize == 0)
mBufSize = cur - mBuffer;
return cur+1;
}
int PWSFKerberosPrincipal::GetPrincipalData(unsigned char **outData, int *outDataLen)
{
int i;
int len = 0;
int datalen = 0;
unsigned char *dataPtr = NULL;
unsigned char *tptr = NULL;
datalen += (sizeof(FILE_HEADER) - 1);
i = 0;
while (mEntries[i] != NULL)
datalen += strlen(mEntries[i++]) + 1;
dataPtr = (unsigned char *) malloc( datalen );
if ( dataPtr == NULL )
return 0;
tptr = dataPtr;
memcpy(tptr, FILE_HEADER, sizeof(FILE_HEADER) - 1);
tptr += sizeof(FILE_HEADER) - 1;
i = 0;
len = strlen(mEntries[i]);
memcpy(tptr, mEntries[i], len);
tptr += len;
i++;
while(mEntries[i] != NULL)
{
*tptr++ = '\t';
len = strlen(mEntries[i]);
memcpy(tptr, mEntries[i], len);
tptr += len;
i++;
}
*tptr++ = '\n';
*outData = dataPtr;
*outDataLen = datalen;
return 1;
}
int PWSFKerberosPrincipal::WritePrincipalToFile(FILE* file)
{
int i;
int len = 0;
len += (sizeof(FILE_HEADER) - 1);
i = 0;
while(mEntries[i] != NULL)
len += strlen(mEntries[i++]) + 1;
len = htonl(len);
i = fwrite(&len, sizeof(len), 1, file);
if (i != 1)
return i;
fprintf(file, FILE_HEADER);
i = 0;
fprintf(file, "%s", mEntries[i++]);
while(mEntries[i] != NULL)
{
fprintf(file, "\t%s", mEntries[i++]);
}
fprintf(file, "\n");
return 1;
}
int PWSFKerberosPrincipal::WritePrincipalToTempFile(int fd)
{
int len = 0;
int i;
i = 0;
while (mEntries[i] != NULL)
len += strlen(mEntries[i++]) + 1;
if (len == 0)
return 0;
char* outBuf = (char*)malloc(len + 1);
char* cur = outBuf;
memcpy(cur, mEntries[0], strlen(mEntries[0]));
cur += strlen(mEntries[0]);
i = 1;
while(mEntries[i] != NULL)
{
*cur++ = '\t';
memcpy(cur, mEntries[i], strlen(mEntries[i]));
cur += strlen(mEntries[i++]);
}
*cur++ = '\n';
*cur = '\0';
write(fd, outBuf, strlen(outBuf));
free(outBuf);
return 1;
}
void PWSFKerberosPrincipal::WritePrincipalToDB()
{
char tempFileName[50];
strcpy(tempFileName, "/var/db/krb5kdc/KerbLoadFileXXXXX");
int fd = mkstemp(tempFileName);
write(fd, FILE_HEADER, sizeof(FILE_HEADER) - 1);
WritePrincipalToTempFile(fd);
close(fd);
char* args[5];
args[0] = "kdb5_util";
args[1] = "load";
args[2] = "-update";
args[3] = tempFileName;
args[4] = NULL;
pwsf_LaunchTaskWithIO(kKDBUtilLocalFilePath, args, NULL, NULL, 0, NULL);
unlink(tempFileName);
}
int PWSFKerberosPrincipal::ReadPrincipalFromDB(char* principalName, PWSFKerberosPrincipal** outKerbPrinc)
{
PWSFKerberosPrincipal* reply = new PWSFKerberosPrincipal;
char* args[5];
int result = 0;
if ( principalName == NULL || principalName[0] == '\0' )
return -1;
if ( outKerbPrinc == NULL )
return -1;
*outKerbPrinc = NULL;
reply->mBuffer = (char*)malloc(2001);
if ( reply->mBuffer == NULL )
return -1;
reply->mBufSize = 2000;
args[0] = "kdb5_util";
args[1] = "dump";
args[2] = "-";
args[3] = principalName;
args[4] = NULL;
result = pwsf_LaunchTaskWithIO(kKDBUtilLocalFilePath, args, NULL, reply->mBuffer, reply->mBufSize, NULL);
if ( (result == 0) && (strlen(reply->mBuffer) > sizeof(FILE_HEADER)) )
{
reply->ParseBuffer(true);
}
else
{
delete reply;
return result;
}
if ((reply->GetName() == NULL) || (strcmp(reply->GetName(), principalName) != 0))
{
delete reply;
reply = NULL;
}
*outKerbPrinc = reply;
return result;
}
PWSFKerberosPrincipal* PWSFKerberosPrincipal::ReadPrincipalFromFile(FILE* file, int recordSize, PWSFKerberosPrincipalList* listOwner)
{
PWSFKerberosPrincipal* reply;
int readCount;
if ( recordSize < 0 || recordSize > 50 * 1024 )
return NULL;
if (listOwner != NULL)
reply = new PWSFKerberosPrincipal(listOwner);
else
reply = new PWSFKerberosPrincipal;
if ( reply != NULL )
{
reply->mBufSize = recordSize;
reply->mBuffer = (char*)malloc(reply->mBufSize + 1);
if ( reply->mBuffer == NULL ) {
delete reply;
return NULL;
}
readCount = fread( reply->mBuffer, reply->mBufSize, 1, file );
if ( readCount != 1 ) {
delete reply;
return NULL;
}
reply->mBuffer[reply->mBufSize] = '\0';
reply->ParseBuffer( true );
}
return reply;
}
PWSFKerberosPrincipal *
PWSFKerberosPrincipal::ReadPrincipalFromData(unsigned char *record, int recordSize, PWSFKerberosPrincipalList* listOwner)
{
PWSFKerberosPrincipal* reply;
if ( recordSize < 0 || recordSize > 50 * 1024 ) {
return NULL;
}
if ( listOwner != NULL )
reply = new PWSFKerberosPrincipal( listOwner );
else
reply = new PWSFKerberosPrincipal;
if ( reply != NULL )
{
reply->mBufSize = recordSize;
reply->mBuffer = (char*)malloc(reply->mBufSize + 1);
if ( reply->mBuffer == NULL ) {
delete reply;
return NULL;
}
memcpy( reply->mBuffer, record, recordSize );
reply->mBuffer[reply->mBufSize] = '\0';
reply->ParseBuffer( true );
}
return reply;
}
char* PWSFKerberosPrincipal::GetEntryCopy(PWSFKerberosPrincipal* otherRecord, int index)
{
if (otherRecord == NULL || otherRecord->mEntries[index] == NULL)
return NULL;
if ( mOtherBuffer != NULL && mOtherBufSize < otherRecord->mBufSize + 1 )
{
free( mOtherBuffer );
mOtherBuffer = NULL;
}
if ( mOtherBuffer == NULL )
{
mOtherBufSize = otherRecord->mBufSize + 1;
mOtherBuffer = (char *) malloc( mOtherBufSize );
}
if ( mOtherBuffer == NULL )
return NULL;
memcpy( mOtherBuffer, otherRecord->mBuffer, otherRecord->mBufSize + 1 );
int offset = (int)(otherRecord->mEntries[index] - otherRecord->mBuffer);
return mOtherBuffer + offset;
}