Darwin-Streaming-Server/APIModules/QTSSAccessModule/AccessChecker.cpp
Darren VanBuren 849723c9cf Add even more of the source
This should be about everything needed to build so far?
2017-03-07 17:14:16 -08:00

426 lines
16 KiB
C++

/*
*
* @APPLE_LICENSE_HEADER_START@
*
* Copyright (c) 1999-2008 Apple Inc. All Rights Reserved.
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*
*/
/*
File: AccessChecker.cpp
Contains:
*/
#include <signal.h>
#ifndef __Win32__
#ifndef __USE_XOPEN
#define __USE_XOPEN 1
#endif
#include <unistd.h>
#endif
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "SafeStdLib.h"
#include "StringParser.h"
#include "OSFileSource.h"
#include "base64.h"
#include "OSMemory.h"
#include "OSHeaders.h"
#include "AccessChecker.h"
#include "QTSSModuleUtils.h"
#include "OSArrayObjectDeleter.h"
static StrPtrLen sAuthWord("realm", 5);
// Constructor
// Allocates no memory
AccessChecker::AccessChecker() :
fGroupsFilePath(NULL),
fUsersFilePath(NULL),
fUsersFileModDate(-1),
fGroupsFileModDate(-1),
fProfiles(NULL),
fNumUsers(0),
fCurrentSize(0)
{
}
// Destructor
// Deletes the fUsersFilePath, fGroupsFilePath,
// and calls the function to delete the authRealm and all the profiles
AccessChecker::~AccessChecker()
{
delete[] fGroupsFilePath;
delete[] fUsersFilePath;
DeleteProfilesAndRealm();
}
// Allocates memory for the fUsersFilePath and fGroupsFilePath
// Before this call is made, make sure that the previous memory allocated is deleted
// or that memory will be orphaned!
void AccessChecker::UpdateFilePaths(const char* inUsersFilePath, const char* inGroupsFilePath) {
// Assert input arguments are not null
Assert(inUsersFilePath != NULL);
Assert(inGroupsFilePath != NULL);
// Before reassigning, delete old paths
delete[] fGroupsFilePath;
delete[] fUsersFilePath;
fUsersFilePath = NEW char[strlen(inUsersFilePath)+1];
::strcpy(fUsersFilePath, inUsersFilePath);
fGroupsFilePath = NEW char[strlen(inGroupsFilePath)+1];
::strcpy(fGroupsFilePath, inGroupsFilePath);
}
// Function to delete memory allocated for all the profiles, and the authRealm
// For each profile, memory is allocated for
// username
// cryptPassword
// digestPassword
// each group that the user belongs to (array of group names)
// All of the above are deleted
void AccessChecker::DeleteProfilesAndRealm()
{
UInt32 i, j;
// delete the profiles
if(fProfiles != NULL)
{
// For each profile
for(i = 0; i < fNumUsers; i++)
{
UserProfile* profile = fProfiles[i];
// delete the username
if((profile->username).Len != 0)
{
delete (profile->username).Ptr;
(profile->username).Len = 0;
}
// delete cryptPassword
if((profile->cryptPassword).Len != 0)
{
delete (profile->cryptPassword).Ptr;
(profile->cryptPassword).Len = 0;
}
// delete digestPassword
if((profile->digestPassword).Len != 0)
{
delete (profile->digestPassword).Ptr;
(profile->digestPassword).Len = 0;
}
// delete each group name
for(j = 0; j < profile->numGroups; j++)
{
delete [] profile->groups[j];
}
// delete the array of pointers to the group names
delete [] profile->groups;
profile->groups = NULL;
profile->maxGroupNameLen = 0;
profile->numGroups = 0;
profile->groupsSize = 0;
delete profile;
}
// delete the array of profile pointers
delete [] fProfiles;
fProfiles = NULL;
}
// delete the fAuthRealm field
if(fAuthRealm.Len != 0) {
delete fAuthRealm.Ptr;
fAuthRealm.Len = 0;
}
fNumUsers = 0;
fCurrentSize = 0;
}
// Memory is allocated for each username record found in the users file
// Memory is also allocated for each group name found in the groups file per user
// All this memory must be deleted if the profiles are deleted, before parsing
// the file again
UInt32 AccessChecker::UpdateUserProfiles() {
UInt32 index = 0;
UInt32 i = 0, j = 0;
UInt32 resultErr = kNoErr;
Bool16 groupFileErrors = true;
Bool16 userFileErrors = true;
StrPtrLen line;
QTSS_TimeVal oldUsersFileModDate = fUsersFileModDate;
QTSS_TimeVal oldGroupsFileModDate = fGroupsFileModDate;
// Read the users file into a buffer
StrPtrLen userData;
QTSS_TimeVal newModDate = -1;
QTSS_Error err = QTSS_NoErr;
// QTSSModuleUtils::ReadEntireFile allocates memory for userData
err = QTSSModuleUtils::ReadEntireFile(fUsersFilePath, &userData, fUsersFileModDate, &newModDate);
if(err == QTSS_FileNotFound)
resultErr |= kUsersFileNotFoundErr;
else if(err != QTSS_NoErr)
resultErr |= kUsersFileUnknownErr;
else
userFileErrors = false;
if(userFileErrors)
fUsersFileModDate = -1;
else if(userData.Len != 0)
fUsersFileModDate = newModDate;
newModDate = -1;
// Read the groups file into a buffer
StrPtrLen groupData;
// QTSSModuleUtils::ReadEntireFile allocates memory for groupData
err = QTSSModuleUtils::ReadEntireFile(fGroupsFilePath, &groupData, fGroupsFileModDate, &newModDate);
if(err == QTSS_FileNotFound)
resultErr |= kGroupsFileNotFoundErr;
else if(err != QTSS_NoErr)
resultErr |= kGroupsFileUnknownErr;
else
groupFileErrors = false;
if(groupFileErrors)
fGroupsFileModDate = -1;
else if(groupData.Len != 0)
fGroupsFileModDate = newModDate;
if(userFileErrors)
{
// delete user profiles and exit
DeleteProfilesAndRealm();
return resultErr;
}
if((fUsersFileModDate == oldUsersFileModDate) && (fGroupsFileModDate == oldGroupsFileModDate))
return resultErr;
// If either the users or groups file has changed
// the old profiles and the old realm should be deleted
// before a new array of profiles is created and a new realm from the users file is read
DeleteProfilesAndRealm();
// Since one or both of the files has changed, reread the files and create user profiles
if(userData.Len == 0)
(void)QTSSModuleUtils::ReadEntireFile(fUsersFilePath, &userData, -1, NULL);
if(groupData.Len == 0 && !groupFileErrors)
(void)QTSSModuleUtils::ReadEntireFile(fGroupsFilePath, &groupData, -1, NULL);
// This will delete the memory allocated for userData when we return from this function
OSCharArrayDeleter userDataPtrDeleter(userData.Ptr);
// This will delete the memory allocated for groupData when we return from this function
OSCharArrayDeleter groupDataPtrDeleter(groupData.Ptr);
// Create the fProfiles array of size kDefaultNumProfiles
fProfiles = NEW UserProfile*[kDefaultNumProfiles];
fCurrentSize = kDefaultNumProfiles;
StringParser userDataParser(&userData);
// check if the first line is "realm"
while(true) {
StrPtrLen word;
userDataParser.GetThruEOL(&line);
StringParser authLineParser(&line);
// Skip over leading whitespace
authLineParser.ConsumeUntil(NULL, StringParser::sWhitespaceMask);
// Skip over comments and blank lines
if ((authLineParser.GetDataRemaining() == 0) || (authLineParser[0] == '#') || (authLineParser[0] == '\0') )
continue;
authLineParser.ConsumeWord(&word);
if(sAuthWord.Equal(word)) {
authLineParser.ConsumeWhitespace();
authLineParser.ConsumeUntil(&word, StringParser::sEOLMask);
fAuthRealm.Set(word.GetAsCString(), word.Len);
}
else {
// This shouldn't happen because it means that the realm line
// is not the first non-commented out line in the file
// Implies the users file is corrupted!
resultErr |= kBadUsersFileErr;
// Create a new user profile for the first username
UserProfile* profile = NEW UserProfile;
profile->groups = NEW char*[kDefaultNumGroups];
profile->maxGroupNameLen = 0;
profile->numGroups = 0;
profile->groupsSize = kDefaultNumGroups;
(profile->username).Set(word.GetAsCString(), word.Len);
// Get the crypted password
if ( authLineParser.Expect(':') )
{
authLineParser.ConsumeUntil(&word, ':');
(profile->cryptPassword).Set(word.GetAsCString(), word.Len);
// Get the digest password
authLineParser.GetThruEOL(&word);
(profile->digestPassword).Set(word.GetAsCString(), word.Len);
}
fProfiles[index] = profile;
index ++;
}
break;
}
while(userDataParser.GetDataRemaining() != 0) {
// Read each line
userDataParser.GetThruEOL(&line);
StringParser userLineParser(&line);
//parse the line
//skip over leading whitespace
userLineParser.ConsumeUntil(NULL, StringParser::sWhitespaceMask);
//skip over comments and blank lines
if ((userLineParser.GetDataRemaining() == 0) || (userLineParser[0] == '#') || (userLineParser[0] == '\0') )
continue;
// Create a new user profile for each username found
UserProfile* profile = NEW UserProfile;
profile->groups = NEW char*[kDefaultNumGroups];
profile->maxGroupNameLen = 0;
profile->numGroups = 0;
profile->groupsSize = kDefaultNumGroups;
StrPtrLen word;
userLineParser.ConsumeUntil(&word, ':');
(profile->username).Set(word.GetAsCString(), word.Len);
// Get the crypted password
if ( userLineParser.Expect(':') )
{
userLineParser.ConsumeUntil(&word, ':');
(profile->cryptPassword).Set(word.GetAsCString(), word.Len);
if(userLineParser.Expect(':')) {
// Get the digest password
userLineParser.GetThruEOL(&word);
(profile->digestPassword).Set(word.GetAsCString(), word.Len);
}
}
if(index >= fCurrentSize) {
UserProfile** oldProfiles = fProfiles;
fProfiles = NEW UserProfile*[fCurrentSize * 2];
for(i = 0; i < fCurrentSize; i++)
{
fProfiles[i] = oldProfiles[i];
}
fCurrentSize *= 2;
delete [] oldProfiles;
}
fProfiles[index] = profile;
index ++;
}
fNumUsers = index;
if(!groupFileErrors)
{
StringParser groupDataParser(&groupData);
while(groupDataParser.GetDataRemaining() != 0) {
// Read each line
groupDataParser.GetThruEOL(&line);
StringParser groupLineParser(&line);
//parse the line
//skip over leading whitespace
groupLineParser.ConsumeUntil(NULL, StringParser::sWhitespaceMask);
//skip over comments and blank lines
if ((groupLineParser.GetDataRemaining() == 0) || (groupLineParser[0] == '#') || (groupLineParser[0] == '\0') )
continue;
//parse the groupname
StrPtrLen groupName;
groupLineParser.ConsumeUntil(&groupName, ':');
if (groupLineParser.Expect(':')) {
StrPtrLen groupUser;
UInt32 nameLen = groupName.Len + 1;
while(groupLineParser.GetDataRemaining() != 0)
{
groupLineParser.ConsumeWhitespace();
groupLineParser.ConsumeUntilWhitespace(&groupUser);
for(i = 0; i < fNumUsers; i++) {
if(fProfiles[i]->username.Equal(groupUser))
{
UInt32 grpSize = fProfiles[i]->groupsSize;
if(fProfiles[i]->numGroups >= grpSize) {
char** oldGroups = fProfiles[i]->groups;
fProfiles[i]->groups = NEW char*[grpSize * 2];
for(j = 0; j < grpSize; j++) {
fProfiles[i]->groups[j] = oldGroups[j];
}
fProfiles[i]->groupsSize *= 2;
delete [] oldGroups;
}
fProfiles[i]->groups[fProfiles[i]->numGroups] = groupName.GetAsCString();
if(nameLen > fProfiles[i]->maxGroupNameLen)
fProfiles[i]->maxGroupNameLen = nameLen;
fProfiles[i]->numGroups++;
break;
}
}
}
}
}
}
return resultErr;
}
// No memory is allocated
Bool16 AccessChecker::HaveFilePathsChanged(const char* inUsersFilePath, const char* inGroupsFilePath)
{
Bool16 changed = true;
if((inUsersFilePath != NULL) && (inGroupsFilePath != NULL) && (fUsersFilePath != NULL) && (fGroupsFilePath != NULL)) {
if((strcmp(inUsersFilePath, fUsersFilePath) == 0) && (strcmp(inGroupsFilePath, fGroupsFilePath) == 0))
changed = false;
}
return changed;
}
// No memory is allocated
AccessChecker::UserProfile* AccessChecker::RetrieveUserProfile(const StrPtrLen* inUserName)
{
UInt32 index = 0;
for(index = 0; index < fNumUsers; index++) {
if(fProfiles[index]->username.Equal(*inUserName))
return fProfiles[index];
}
return NULL;
}