Darwin-Streaming-Server/APIModules/QTSSAdminModule/QTSSAdminModule.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

1049 lines
38 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: QTSSAdminModule.cpp
Contains: Implements Admin module
*/
#ifndef __Win32__
#include <unistd.h> /* for getopt() et al */
#endif
#include <time.h>
#include <stdio.h> /* for qtss_printf */
#include <stdlib.h> /* for getloadavg & other useful stuff */
#include "QTSSAdminModule.h"
#include "OSArrayObjectDeleter.h"
#include "StringParser.h"
#include "StrPtrLen.h"
#include "QTSSModuleUtils.h"
#include "OSHashTable.h"
#include "OSMutex.h"
#include "StrPtrLen.h"
#include "OSRef.h"
#include "AdminElementNode.h"
#include "base64.h"
#include "OSMemory.h"
#include "md5.h"
#include "md5digest.h"
#if __MacOSX__
#include <Security/Authorization.h>
#include <Security/AuthorizationTags.h>
#endif
#if __solaris__ || __linux__ || __sgi__ || __hpux__
#include <crypt.h>
#endif
#define DEBUG_ADMIN_MODULE 0
//**************************************************
#define kAuthNameAndPasswordBuffSize 512
#define kPasswordBuffSize kAuthNameAndPasswordBuffSize/2
// STATIC DATA
//**************************************************
#if DEBUG_ADMIN_MODULE
static UInt32 sRequestCount= 0;
#endif
static QTSS_Initialize_Params sQTSSparams;
//static char* sResponseHeader = "HTTP/1.0 200 OK\r\nServer: QTSS\r\nConnection: Close\r\nContent-Type: text/plain\r\n\r\n";
static char* sResponseHeader = "HTTP/1.0 200 OK";
static char* sUnauthorizedResponseHeader = "HTTP/1.1 401 Unauthorized\r\nWWW-Authenticate: Basic realm=\"QTSS/modules/admin\"\r\nServer: QTSS\r\nConnection: Close\r\nContent-Type: text/plain\r\n\r\n";
static char* sPermissionDeniedHeader = "HTTP/1.1 403 Forbidden\r\nConnection: Close\r\nContent-Type: text/html\r\n\r\n";
static char* sHTMLBody = "<HTML><BODY>\n<P><b>Your request was denied by the server.</b></P>\n</BODY></HTML>\r\n\r\n";
static char* sVersionHeader = NULL;
static char* sConnectionHeader = "Connection: Close";
static char* kDefaultHeader = "Server: QTSS";
static char* sContentType = "Content-Type: text/plain";
static char* sEOL = "\r\n";
static char* sEOM = "\r\n\r\n";
static char* sAuthRealm = "QTSS/modules/admin";
static char* sAuthResourceLocalPath = "/modules/admin/";
static QTSS_ServerObject sServer = NULL;
static QTSS_ModuleObject sModule = NULL;
static QTSS_ModulePrefsObject sModulePrefs = NULL;
static QTSS_PrefsObject sServerPrefs = NULL;
static AdminClass *sAdminPtr = NULL;
static QueryURI *sQueryPtr = NULL;
static OSMutex* sAdminMutex = NULL;//admin module isn't reentrant
static UInt32 sVersion=20030306;
static char *sDesc="Implements HTTP based Admin Protocol for accessing server attributes";
static char decodedLine[kAuthNameAndPasswordBuffSize] = { 0 };
static char codedLine[kAuthNameAndPasswordBuffSize] = { 0 };
static QTSS_TimeVal sLastRequestTime = 0;
static UInt32 sSessID = 0;
static StrPtrLen sAuthRef("AuthRef");
#if __MacOSX__
static char* sSecurityServerAuthKey = "com.apple.server.admin.streaming";
static AuthorizationItem sRight = { sSecurityServerAuthKey, 0, NULL, 0 };
static AuthorizationRights sRightSet = { 1, &sRight };
#endif
// ATTRIBUTES
//**************************************************
enum { kMaxRequestTimeIntervalMilli = 1000, kDefaultRequestTimeIntervalMilli = 50 };
static UInt32 sDefaultRequestTimeIntervalMilli = kDefaultRequestTimeIntervalMilli;
static UInt32 sRequestTimeIntervalMilli = kDefaultRequestTimeIntervalMilli;
static Bool16 sAuthenticationEnabled = true;
static Bool16 sDefaultAuthenticationEnabled = true;
static Bool16 sLocalLoopBackOnlyEnabled = true;
static Bool16 sDefaultLocalLoopBackOnlyEnabled = true;
static Bool16 sEnableRemoteAdmin = true;
static Bool16 sDefaultEnableRemoteAdmin = true;
static QTSS_AttributeID sIPAccessListID = qtssIllegalAttrID;
static char* sIPAccessList = NULL;
static char* sLocalLoopBackAddress = "127.0.0.*";
static char* sAdministratorGroup = NULL;
static char* sDefaultAdministratorGroup = "admin";
static Bool16 sFlushing = false;
static QTSS_AttributeID sFlushingID = qtssIllegalAttrID;
static char* sFlushingName = "QTSSAdminModuleFlushingState";
static UInt32 sFlushingLen = sizeof(sFlushing);
static QTSS_AttributeID sAuthenticatedID = qtssIllegalAttrID;
static char* sAuthenticatedName = "QTSSAdminModuleAuthenticatedState";
//**************************************************
static QTSS_Error QTSSAdminModuleDispatch(QTSS_Role inRole, QTSS_RoleParamPtr inParams);
static QTSS_Error Register(QTSS_Register_Params* inParams);
static QTSS_Error Initialize(QTSS_Initialize_Params* inParams);
static QTSS_Error FilterRequest(QTSS_Filter_Params* inParams);
static QTSS_Error RereadPrefs();
static QTSS_Error AuthorizeAdminRequest(QTSS_RTSPRequestObject request);
static Bool16 AcceptSession(QTSS_RTSPSessionObject inRTSPSession);
#if !DEBUG_ADMIN_MODULE
#define APITests_DEBUG()
#define ShowQuery_DEBUG()
#else
void ShowQuery_DEBUG()
{
qtss_printf("======REQUEST #%"_U32BITARG_"======\n",++sRequestCount);
StrPtrLen* aStr;
aStr = sQueryPtr->GetURL();
qtss_printf("URL="); PRINT_STR(aStr);
aStr = sQueryPtr->GetQuery();
qtss_printf("Query="); PRINT_STR(aStr);
aStr = sQueryPtr->GetParameters();
qtss_printf("Parameters="); PRINT_STR(aStr);
aStr = sQueryPtr->GetCommand();
qtss_printf("Command="); PRINT_STR(aStr);
qtss_printf("CommandID=%"_S32BITARG_" \n",sQueryPtr->GetCommandID());
aStr = sQueryPtr->GetValue();
qtss_printf("Value="); PRINT_STR(aStr);
aStr = sQueryPtr->GetType();
qtss_printf("Type="); PRINT_STR(aStr);
aStr = sQueryPtr->GetAccess();
qtss_printf("Access="); PRINT_STR(aStr);
}
void APITests_DEBUG()
{
if (0)
{ qtss_printf("QTSSAdminModule start tests \n");
if (0)
{
qtss_printf("admin called locked \n");
const int ksleeptime = 15;
qtss_printf("sleeping for %d seconds \n",ksleeptime);
sleep(ksleeptime);
qtss_printf("done sleeping \n");
qtss_printf("QTSS_GlobalUnLock \n");
(void) QTSS_GlobalUnLock();
qtss_printf("again sleeping for %d seconds \n",ksleeptime);
sleep(ksleeptime);
}
if (0)
{
qtss_printf(" GET VALUE PTR TEST \n");
QTSS_Object *sessionsPtr = NULL;
UInt32 paramLen = sizeof(sessionsPtr);
UInt32 numValues = 0;
QTSS_Error err = 0;
err = QTSS_GetNumValues (sServer, qtssSvrClientSessions, &numValues);
err = QTSS_GetValuePtr(sServer, qtssSvrClientSessions, 0, (void**)&sessionsPtr, &paramLen);
qtss_printf("Admin Module Num Sessions = %"_U32BITARG_" sessions[0] = %"_S32BITARG_" err = %"_S32BITARG_" paramLen =%"_U32BITARG_"\n", numValues, (SInt32) *sessionsPtr,err,paramLen);
UInt32 numAttr = 0;
if (sessionsPtr)
{ err = QTSS_GetNumAttributes (*sessionsPtr, &numAttr);
qtss_printf("Admin Module Num attributes = %"_U32BITARG_" sessions[0] = %"_S32BITARG_" err = %"_S32BITARG_"\n", numAttr, (SInt32) *sessionsPtr,err);
QTSS_Object theAttributeInfo;
char nameBuff[128];
UInt32 len = 127;
for (UInt32 i = 0; i < numAttr; i++)
{ err = QTSS_GetAttrInfoByIndex(*sessionsPtr, i, &theAttributeInfo);
nameBuff[0] = 0;len = 127;
err = QTSS_GetValue (theAttributeInfo, qtssAttrName,0, nameBuff,&len);
nameBuff[len] = 0;
qtss_printf("found %s \n",nameBuff);
}
}
}
if (0)
{
qtss_printf(" GET VALUE TEST \n");
QTSS_Object sessions = NULL;
UInt32 paramLen = sizeof(sessions);
UInt32 numValues = 0;
QTSS_Error err = 0;
err = QTSS_GetNumValues (sServer, qtssSvrClientSessions, &numValues);
err = QTSS_GetValue(sServer, qtssSvrClientSessions, 0, (void*)&sessions, &paramLen);
qtss_printf("Admin Module Num Sessions = %"_U32BITARG_" sessions[0] = %"_S32BITARG_" err = %"_S32BITARG_" paramLen = %"_U32BITARG_"\n", numValues, (SInt32) sessions,err, paramLen);
if (sessions)
{
UInt32 numAttr = 0;
err = QTSS_GetNumAttributes (sessions, &numAttr);
qtss_printf("Admin Module Num attributes = %"_U32BITARG_" sessions[0] = %"_S32BITARG_" err = %"_S32BITARG_"\n", numAttr,(SInt32) sessions,err);
QTSS_Object theAttributeInfo;
char nameBuff[128];
UInt32 len = 127;
for (UInt32 i = 0; i < numAttr; i++)
{ err = QTSS_GetAttrInfoByIndex(sessions, i, &theAttributeInfo);
nameBuff[0] = 0;len = 127;
err = QTSS_GetValue (theAttributeInfo, qtssAttrName,0, nameBuff,&len);
nameBuff[len] = 0;
qtss_printf("found %s \n",nameBuff);
}
}
}
if (0)
{
qtss_printf("----------------- Start test ----------------- \n");
qtss_printf(" GET indexed pref TEST \n");
QTSS_Error err = 0;
UInt32 numAttr = 1;
err = QTSS_GetNumAttributes (sModulePrefs, &numAttr);
qtss_printf("Admin Module Num preference attributes = %"_U32BITARG_" err = %"_S32BITARG_"\n", numAttr, err);
QTSS_Object theAttributeInfo;
char valueBuff[512];
char nameBuff[128];
QTSS_AttributeID theID;
UInt32 len = 127;
UInt32 i = 0;
qtss_printf("first pass over preferences\n");
for ( i = 0; i < numAttr; i++)
{ err = QTSS_GetAttrInfoByIndex(sModulePrefs, i, &theAttributeInfo);
nameBuff[0] = 0;len = 127;
err = QTSS_GetValue (theAttributeInfo, qtssAttrName,0, nameBuff,&len);
nameBuff[len]=0;
theID = qtssIllegalAttrID; len = sizeof(theID);
err = QTSS_GetValue (theAttributeInfo, qtssAttrID,0, &theID,&len);
qtss_printf("found preference=%s \n",nameBuff);
}
valueBuff[0] = 0;len = 512;
err = QTSS_GetValue (sModulePrefs, theID,0, valueBuff,&len);valueBuff[len] = 0;
qtss_printf("Admin Module QTSS_GetValue name = %s id = %"_S32BITARG_" value=%s err = %"_S32BITARG_"\n", nameBuff,theID, valueBuff, err);
err = QTSS_SetValue (sModulePrefs,theID,0, valueBuff,len);
qtss_printf("Admin Module QTSS_SetValue name = %s id = %"_S32BITARG_" value=%s err = %"_S32BITARG_"\n", nameBuff,theID, valueBuff, err);
{ QTSS_ServiceID id;
(void) QTSS_IDForService(QTSS_REREAD_PREFS_SERVICE, &id);
(void) QTSS_DoService(id, NULL);
}
valueBuff[0] = 0;len = 512;
err = QTSS_GetValue (sModulePrefs, theID,0, valueBuff,&len);valueBuff[len] = 0;
qtss_printf("Admin Module QTSS_GetValue name = %s id = %"_S32BITARG_" value=%s err = %"_S32BITARG_"\n", nameBuff,theID, valueBuff, err);
err = QTSS_SetValue (sModulePrefs,theID,0, valueBuff,len);
qtss_printf("Admin Module QTSS_SetValue name = %s id = %"_S32BITARG_" value=%s err = %"_S32BITARG_"\n", nameBuff,theID, valueBuff, err);
qtss_printf("second pass over preferences\n");
for ( i = 0; i < numAttr; i++)
{ err = QTSS_GetAttrInfoByIndex(sModulePrefs, i, &theAttributeInfo);
nameBuff[0] = 0;len = 127;
err = QTSS_GetValue (theAttributeInfo, qtssAttrName,0, nameBuff,&len);
nameBuff[len]=0;
theID = qtssIllegalAttrID; len = sizeof(theID);
err = QTSS_GetValue (theAttributeInfo, qtssAttrID,0, &theID,&len);
qtss_printf("found preference=%s \n",nameBuff);
}
qtss_printf("----------------- Done test ----------------- \n");
}
}
}
#endif
inline void KeepSession(QTSS_RTSPRequestObject theRequest,Bool16 keep)
{
(void)QTSS_SetValue(theRequest, qtssRTSPReqRespKeepAlive, 0, &keep, sizeof(keep));
}
// FUNCTION IMPLEMENTATIONS
QTSS_Error QTSSAdminModule_Main(void* inPrivateArgs)
{
return _stublibrary_main(inPrivateArgs, QTSSAdminModuleDispatch);
}
QTSS_Error QTSSAdminModuleDispatch(QTSS_Role inRole, QTSS_RoleParamPtr inParams)
{
switch (inRole)
{
case QTSS_Register_Role:
return Register(&inParams->regParams);
case QTSS_Initialize_Role:
return Initialize(&inParams->initParams);
case QTSS_RTSPFilter_Role:
{ if (!sEnableRemoteAdmin)
break;
return FilterRequest(&inParams->rtspFilterParams);
}
case QTSS_RTSPAuthorize_Role:
return AuthorizeAdminRequest(inParams->rtspRequestParams.inRTSPRequest);
case QTSS_RereadPrefs_Role:
return RereadPrefs();
}
return QTSS_NoErr;
}
QTSS_Error Register(QTSS_Register_Params* inParams)
{
// Do role & attribute setup
(void)QTSS_AddRole(QTSS_Initialize_Role);
(void)QTSS_AddRole(QTSS_RTSPFilter_Role);
(void)QTSS_AddRole(QTSS_RereadPrefs_Role);
(void)QTSS_AddRole(QTSS_RTSPAuthorize_Role);
(void)QTSS_AddStaticAttribute(qtssRTSPRequestObjectType, sFlushingName, NULL, qtssAttrDataTypeBool16);
(void)QTSS_IDForAttr(qtssRTSPRequestObjectType, sFlushingName, &sFlushingID);
(void)QTSS_AddStaticAttribute(qtssRTSPRequestObjectType, sAuthenticatedName, NULL, qtssAttrDataTypeBool16);
(void)QTSS_IDForAttr(qtssRTSPRequestObjectType, sAuthenticatedName, &sAuthenticatedID);
// Tell the server our name!
static char* sModuleName = "QTSSAdminModule";
::strcpy(inParams->outModuleName, sModuleName);
return QTSS_NoErr;
}
QTSS_Error RereadPrefs()
{
delete [] sVersionHeader;
sVersionHeader = QTSSModuleUtils::GetStringAttribute(sServer, "qtssSvrRTSPServerHeader", kDefaultHeader);
delete [] sIPAccessList;
sIPAccessList = QTSSModuleUtils::GetStringAttribute(sModulePrefs, "IPAccessList", sLocalLoopBackAddress);
sIPAccessListID = QTSSModuleUtils::GetAttrID(sModulePrefs, "IPAccessList");
QTSSModuleUtils::GetAttribute(sModulePrefs, "Authenticate", qtssAttrDataTypeBool16, &sAuthenticationEnabled, &sDefaultAuthenticationEnabled, sizeof(sAuthenticationEnabled));
QTSSModuleUtils::GetAttribute(sModulePrefs, "LocalAccessOnly", qtssAttrDataTypeBool16, &sLocalLoopBackOnlyEnabled, &sDefaultLocalLoopBackOnlyEnabled, sizeof(sLocalLoopBackOnlyEnabled));
QTSSModuleUtils::GetAttribute(sModulePrefs, "RequestTimeIntervalMilli", qtssAttrDataTypeUInt32, &sRequestTimeIntervalMilli, &sDefaultRequestTimeIntervalMilli, sizeof(sRequestTimeIntervalMilli));
QTSSModuleUtils::GetAttribute(sModulePrefs, "enable_remote_admin", qtssAttrDataTypeBool16, &sEnableRemoteAdmin, &sDefaultEnableRemoteAdmin, sizeof(sDefaultEnableRemoteAdmin));
delete [] sAdministratorGroup;
sAdministratorGroup = QTSSModuleUtils::GetStringAttribute(sModulePrefs, "AdministratorGroup", sDefaultAdministratorGroup);
if (sRequestTimeIntervalMilli > kMaxRequestTimeIntervalMilli)
{ sRequestTimeIntervalMilli = kMaxRequestTimeIntervalMilli;
}
(void)QTSS_SetValue(sModule, qtssModDesc, 0, sDesc, strlen(sDesc)+1);
(void)QTSS_SetValue(sModule, qtssModVersion, 0, &sVersion, sizeof(sVersion));
return QTSS_NoErr;
}
QTSS_Error Initialize(QTSS_Initialize_Params* inParams)
{
sAdminMutex = NEW OSMutex();
ElementNode_InitPtrArray();
// Setup module utils
QTSSModuleUtils::Initialize(inParams->inMessages, inParams->inServer, inParams->inErrorLogStream);
sQTSSparams = *inParams;
sServer = inParams->inServer;
sModule = inParams->inModule;
sModulePrefs = QTSSModuleUtils::GetModulePrefsObject(sModule);
sServerPrefs = inParams->inPrefs;
RereadPrefs();
return QTSS_NoErr;
}
void ReportErr(QTSS_Filter_Params* inParams, UInt32 err)
{
StrPtrLen* urlPtr = sQueryPtr->GetURL();
StrPtrLen* evalMessagePtr = sQueryPtr->GetEvalMsg();
char temp[32];
if (urlPtr && evalMessagePtr)
{ qtss_sprintf(temp,"(%"_U32BITARG_")",err);
(void)QTSS_Write(inParams->inRTSPRequest, "error:", strlen("error:"), NULL, 0);
(void)QTSS_Write(inParams->inRTSPRequest, temp, strlen(temp), NULL, 0);
if (sQueryPtr->VerboseParam())
{ (void)QTSS_Write(inParams->inRTSPRequest, ";URL=", strlen(";URL="), NULL, 0);
if (urlPtr) (void)QTSS_Write(inParams->inRTSPRequest, urlPtr->Ptr, urlPtr->Len, NULL, 0);
}
if (sQueryPtr->DebugParam())
{
(void)QTSS_Write(inParams->inRTSPRequest, ";", strlen(";"), NULL, 0);
(void)QTSS_Write(inParams->inRTSPRequest, evalMessagePtr->Ptr, evalMessagePtr->Len, NULL, 0);
}
(void)QTSS_Write(inParams->inRTSPRequest, "\r\n\r\n", 4, NULL, 0);
}
}
inline Bool16 AcceptAddress(StrPtrLen *theAddressPtr)
{
IPComponentStr ipComponentStr(theAddressPtr);
Bool16 isLocalRequest = ipComponentStr.IsLocal();
if (sLocalLoopBackOnlyEnabled && isLocalRequest)
return true;
if (sLocalLoopBackOnlyEnabled && !isLocalRequest)
return false;
if (QTSSModuleUtils::AddressInList(sModulePrefs, sIPAccessListID, theAddressPtr))
return true;
return false;
}
inline Bool16 IsAdminRequest(StringParser *theFullRequestPtr)
{
Bool16 handleRequest = false;
if (theFullRequestPtr != NULL) do
{
StrPtrLen strPtr;
theFullRequestPtr->ConsumeWord(&strPtr);
if ( !strPtr.Equal(StrPtrLen("GET")) ) break; //it's a "Get" request
theFullRequestPtr->ConsumeWhitespace();
if ( !theFullRequestPtr->Expect('/') ) break;
theFullRequestPtr->ConsumeWord(&strPtr);
if ( strPtr.Len == 0 || !strPtr.Equal(StrPtrLen("modules") ) ) break;
if (!theFullRequestPtr->Expect('/') ) break;
theFullRequestPtr->ConsumeWord(&strPtr);
if ( strPtr.Len == 0 || !strPtr.Equal(StrPtrLen("admin") ) ) break;
handleRequest = true;
} while (false);
return handleRequest;
}
inline void ParseAuthNameAndPassword(StrPtrLen *codedStrPtr, StrPtrLen* namePtr, StrPtrLen* passwordPtr)
{
if (!codedStrPtr || (codedStrPtr->Len >= kAuthNameAndPasswordBuffSize) )
{ return;
}
StrPtrLen codedLineStr;
StrPtrLen nameAndPassword;
memset(decodedLine,0,kAuthNameAndPasswordBuffSize);
memset(codedLine,0,kAuthNameAndPasswordBuffSize);
memcpy (codedLine,codedStrPtr->Ptr,codedStrPtr->Len);
codedLineStr.Set((char*) codedLine, codedStrPtr->Len);
(void) Base64decode(decodedLine, codedLineStr.Ptr);
nameAndPassword.Set((char*) decodedLine, strlen(decodedLine));
StringParser parsedNameAndPassword(&nameAndPassword);
parsedNameAndPassword.ConsumeUntil(namePtr,':');
parsedNameAndPassword.ConsumeLength(NULL, 1);
// password can have whitespace, so read until the end of the line, not just until whitespace
parsedNameAndPassword.ConsumeUntil(passwordPtr, StringParser::sEOLMask);
namePtr->Ptr[namePtr->Len]= 0;
passwordPtr->Ptr[passwordPtr->Len]= 0;
//qtss_printf("decoded nameAndPassword="); PRINT_STR(&nameAndPassword);
//qtss_printf("decoded name="); PRINT_STR(namePtr);
//qtss_printf("decoded password="); PRINT_STR(passwordPtr);
return;
};
inline Bool16 OSXAuthenticate(StrPtrLen *keyStrPtr)
{
#if __MacOSX__
// Authorization: AuthRef QWxhZGRpbjpvcGVuIHNlc2FtZQ==
Bool16 result = false;
if (keyStrPtr == NULL || keyStrPtr->Len == 0)
return result;
char *encodedKey = keyStrPtr->GetAsCString();
OSCharArrayDeleter encodedKeyDeleter(encodedKey);
char *decodedKey = NEW char[Base64decode_len(encodedKey) + 1];
OSCharArrayDeleter decodedKeyDeleter(decodedKey);
(void) Base64decode(decodedKey, encodedKey);
AuthorizationExternalForm *receivedExtFormPtr = (AuthorizationExternalForm *) decodedKey;
AuthorizationRef receivedAuthorization;
OSStatus status = AuthorizationCreateFromExternalForm(receivedExtFormPtr, &receivedAuthorization);
if (status != errAuthorizationSuccess)
return result;
status = AuthorizationCopyRights(receivedAuthorization, &sRightSet, kAuthorizationEmptyEnvironment, kAuthorizationFlagExtendRights , NULL);
if (status == errAuthorizationSuccess)
{
result = true;
}
AuthorizationFree(receivedAuthorization, kAuthorizationFlagDestroyRights);
return result;
#else
return false;
#endif
}
inline Bool16 HasAuthentication(StringParser *theFullRequestPtr, StrPtrLen* namePtr, StrPtrLen* passwordPtr, StrPtrLen* outAuthTypePtr)
{
// Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
Bool16 hasAuthentication = false;
StrPtrLen strPtr;
StrPtrLen authType;
StrPtrLen authString;
while (theFullRequestPtr->GetDataRemaining() > 0)
{
theFullRequestPtr->ConsumeWhitespace();
theFullRequestPtr->ConsumeUntilWhitespace(&strPtr);
if ( strPtr.Len == 0 || !strPtr.Equal(StrPtrLen("Authorization:")) )
continue;
theFullRequestPtr->ConsumeWhitespace();
theFullRequestPtr->ConsumeUntilWhitespace(&authType);
if ( authType.Len == 0 )
continue;
theFullRequestPtr->ConsumeWhitespace();
theFullRequestPtr->ConsumeUntil(&authString, StringParser::sEOLMask);
if ( authString.Len == 0 )
continue;
if (outAuthTypePtr != NULL)
outAuthTypePtr->Set(authType.Ptr, authType.Len);
if (authType.Equal(StrPtrLen("Basic") ) )
{
(void) ParseAuthNameAndPassword(&authString,namePtr, passwordPtr);
if (namePtr->Len == 0)
continue;
hasAuthentication = true;
break;
}
else if (authType.Equal(sAuthRef) )
{
namePtr->Set(NULL,0);
passwordPtr->Set(authString.Ptr, authString.Len);
hasAuthentication = true;
break;
}
};
return hasAuthentication;
}
Bool16 Authenticate(QTSS_RTSPRequestObject request, StrPtrLen* namePtr, StrPtrLen* passwordPtr)
{
Bool16 authenticated = true;
char* authName = namePtr->GetAsCString();
OSCharArrayDeleter authNameDeleter(authName);
QTSS_ActionFlags authAction = qtssActionFlagsAdmin;
// authenticate callback to retrieve the password
QTSS_Error err = QTSS_Authenticate(authName, sAuthResourceLocalPath, sAuthResourceLocalPath, authAction, qtssAuthBasic, request);
if (err != QTSS_NoErr) {
return false; // Couldn't even call QTSS_Authenticate...abandon!
}
// Get the user profile object from the request object that was created in the authenticate callback
QTSS_UserProfileObject theUserProfile = NULL;
UInt32 len = sizeof(QTSS_UserProfileObject);
err = QTSS_GetValue(request, qtssRTSPReqUserProfile, 0, (void*)&theUserProfile, &len);
Assert(len == sizeof(QTSS_UserProfileObject));
if (err != QTSS_NoErr)
authenticated = false;
if(err == QTSS_NoErr) {
char* reqPassword = passwordPtr->GetAsCString();
OSCharArrayDeleter reqPasswordDeleter(reqPassword);
char* userPassword = NULL;
(void) QTSS_GetValueAsString(theUserProfile, qtssUserPassword, 0, &userPassword);
OSCharArrayDeleter userPasswordDeleter(userPassword);
if(userPassword == NULL) {
authenticated = false;
}
else {
#ifdef __Win32__
// The password is md5 encoded for win32
char md5EncodeResult[120];
MD5Encode(reqPassword, userPassword, md5EncodeResult, sizeof(md5EncodeResult));
if(::strcmp(userPassword, md5EncodeResult) != 0)
authenticated = false;
#else
if(::strcmp(userPassword, (char*)crypt(reqPassword, userPassword)) != 0)
authenticated = false;
#endif
}
}
char* realm = NULL;
Bool16 allowed = true;
//authorize callback to check authorization
// allocates memory for realm
err = QTSS_Authorize(request, &realm, &allowed);
// QTSS_Authorize allocates memory for the realm string
// we don't use the realm returned by the callback, but instead
// use our own.
// delete the memory allocated for realm because we don't need it!
OSCharArrayDeleter realmDeleter(realm);
if(err != QTSS_NoErr) {
qtss_printf("QTSSAdminModule::Authenticate: QTSS_Authorize failed\n");
return false; // Couldn't even call QTSS_Authorize...abandon!
}
if(authenticated && allowed)
return true;
return false;
}
QTSS_Error AuthorizeAdminRequest(QTSS_RTSPRequestObject request)
{
Bool16 allowed = false;
// get the resource path
// if the path does not match the admin path, don't handle the request
char* resourcePath = QTSSModuleUtils::GetLocalPath_Copy(request);
OSCharArrayDeleter resourcePathDeleter(resourcePath);
if(strcmp(sAuthResourceLocalPath, resourcePath) != 0)
return QTSS_NoErr;
// get the type of request
QTSS_ActionFlags action = QTSSModuleUtils::GetRequestActions(request);
if(!(action & qtssActionFlagsAdmin))
return QTSS_RequestFailed;
QTSS_UserProfileObject theUserProfile = QTSSModuleUtils::GetUserProfileObject(request);
if (NULL == theUserProfile)
return QTSS_RequestFailed;
(void) QTSS_SetValue(request,qtssRTSPReqURLRealm, 0, sAuthRealm, ::strlen(sAuthRealm));
// Authorize the user if the user belongs to the AdministratorGroup (this is an admin module pref)
UInt32 numGroups = 0;
char** groupsArray = QTSSModuleUtils::GetGroupsArray_Copy(theUserProfile, &numGroups);
if ((groupsArray != NULL) && (numGroups != 0))
{
UInt32 index = 0;
for (index = 0; index < numGroups; index++)
{
if(strcmp(sAdministratorGroup, groupsArray[index]) == 0)
{
allowed = true;
break;
}
}
// delete the memory allocated in QTSSModuleUtils::GetGroupsArray_Copy call
delete [] groupsArray;
}
if(!allowed)
{
if (QTSS_NoErr != QTSS_SetValue(request,qtssRTSPReqUserAllowed, 0, &allowed, sizeof(allowed)))
return QTSS_RequestFailed; // Bail on the request. The Server will handle the error
}
return QTSS_NoErr;
}
Bool16 AcceptSession(QTSS_RTSPSessionObject inRTSPSession)
{
char remoteAddress[20] = {0};
StrPtrLen theClientIPAddressStr(remoteAddress,sizeof(remoteAddress));
QTSS_Error err = QTSS_GetValue(inRTSPSession, qtssRTSPSesRemoteAddrStr, 0, (void*)theClientIPAddressStr.Ptr, &theClientIPAddressStr.Len);
if (err != QTSS_NoErr) return false;
return AcceptAddress(&theClientIPAddressStr);
}
Bool16 StillFlushing(QTSS_Filter_Params* inParams,Bool16 flushing)
{
QTSS_Error err = QTSS_NoErr;
if (flushing)
{
err = QTSS_Flush(inParams->inRTSPRequest);
//qtss_printf("Flushing session=%"_U32BITARG_" QTSS_Flush err =%"_S32BITARG_"\n",sSessID,err);
}
if (err == QTSS_WouldBlock) // more to flush later
{
sFlushing = true;
(void) QTSS_SetValue(inParams->inRTSPRequest, sFlushingID, 0, (void*)&sFlushing, sFlushingLen);
err = QTSS_RequestEvent(inParams->inRTSPRequest, QTSS_WriteableEvent);
KeepSession(inParams->inRTSPRequest,true);
//qtss_printf("Flushing session=%"_U32BITARG_" QTSS_RequestEvent err =%"_S32BITARG_"\n",sSessID,err);
}
else
{
sFlushing = false;
(void) QTSS_SetValue(inParams->inRTSPRequest, sFlushingID, 0, (void*)&sFlushing, sFlushingLen);
KeepSession(inParams->inRTSPRequest,false);
if (flushing) // we were flushing so reset the LastRequestTime
{
sLastRequestTime = QTSS_Milliseconds();
//qtss_printf("Done Flushing session=%"_U32BITARG_"\n",sSessID);
return true;
}
}
return sFlushing;
}
Bool16 IsAuthentic(QTSS_Filter_Params* inParams,StringParser *fullRequestPtr)
{
Bool16 isAuthentic = false;
if (!sAuthenticationEnabled) // no authentication
{
isAuthentic = true;
}
else // must authenticate
{
StrPtrLen theClientIPAddressStr;
(void) QTSS_GetValuePtr(inParams->inRTSPSession, qtssRTSPSesRemoteAddrStr, 0, (void**)&theClientIPAddressStr.Ptr, &theClientIPAddressStr.Len);
Bool16 isLocal = IPComponentStr(&theClientIPAddressStr).IsLocal();
StrPtrLen authenticateName;
StrPtrLen authenticatePassword;
StrPtrLen authType;
Bool16 hasAuthentication = HasAuthentication(fullRequestPtr,&authenticateName,&authenticatePassword, &authType);
if (hasAuthentication)
{
if (authType.Equal(sAuthRef))
{
if (isLocal)
isAuthentic = OSXAuthenticate(&authenticatePassword);
}
else
isAuthentic = Authenticate(inParams->inRTSPRequest, &authenticateName,&authenticatePassword);
}
}
// if (isAuthentic)
// isAuthentic = AuthorizeAdminRequest(inParams->inRTSPRequest);
(void) QTSS_SetValue(inParams->inRTSPRequest, sAuthenticatedID, 0, (void*)&isAuthentic, sizeof(isAuthentic));
return isAuthentic;
}
inline Bool16 InWaitInterval(QTSS_Filter_Params* inParams)
{
QTSS_TimeVal nextExecuteTime = sLastRequestTime + sRequestTimeIntervalMilli;
QTSS_TimeVal currentTime = QTSS_Milliseconds();
SInt32 waitTime = 0;
if (currentTime < nextExecuteTime)
{
waitTime = (SInt32) (nextExecuteTime - currentTime) + 1;
//qtss_printf("(currentTime < nextExecuteTime) sSessID = %"_U32BITARG_" waitTime =%"_S32BITARG_" currentTime = %qd nextExecute = %qd interval=%"_U32BITARG_"\n",sSessID, waitTime, currentTime, nextExecuteTime,sRequestTimeIntervalMilli);
(void)QTSS_SetIdleTimer(waitTime);
KeepSession(inParams->inRTSPRequest,true);
//qtss_printf("-- call me again after %"_S32BITARG_" millisecs session=%"_U32BITARG_" \n",waitTime,sSessID);
return true;
}
sLastRequestTime = QTSS_Milliseconds();
//qtss_printf("handle sessID=%"_U32BITARG_" time=%qd \n",sSessID,currentTime);
return false;
}
inline void GetQueryData(QTSS_RTSPRequestObject theRequest)
{
sAdminPtr = NEW AdminClass();
Assert(sAdminPtr != NULL);
if (sAdminPtr == NULL)
{ //qtss_printf ("NEW AdminClass() failed!! \n");
return;
}
if (sAdminPtr != NULL)
{
sAdminPtr->Initialize(&sQTSSparams,sQueryPtr); // Get theData
}
}
inline void SendHeader(QTSS_StreamRef inStream)
{
(void)QTSS_Write(inStream, sResponseHeader, ::strlen(sResponseHeader), NULL, 0);
(void)QTSS_Write(inStream, sEOL, ::strlen(sEOL), NULL, 0);
(void)QTSS_Write(inStream, sVersionHeader, ::strlen(sVersionHeader), NULL, 0);
(void)QTSS_Write(inStream, sEOL, ::strlen(sEOL), NULL, 0);
(void)QTSS_Write(inStream, sConnectionHeader, ::strlen(sConnectionHeader), NULL, 0);
(void)QTSS_Write(inStream, sEOL, ::strlen(sEOL), NULL, 0);
(void)QTSS_Write(inStream, sContentType, ::strlen(sContentType), NULL, 0);
(void)QTSS_Write(inStream, sEOM, ::strlen(sEOM), NULL, 0);
}
inline void SendResult(QTSS_StreamRef inStream)
{
SendHeader(inStream);
if (sAdminPtr != NULL)
sAdminPtr->RespondToQuery(inStream,sQueryPtr,sQueryPtr->GetRootID());
}
inline Bool16 GetRequestAuthenticatedState(QTSS_Filter_Params* inParams)
{
Bool16 result = false;
UInt32 paramLen = sizeof(result);
QTSS_Error err = QTSS_GetValue(inParams->inRTSPRequest, sAuthenticatedID, 0, (void*)&result, &paramLen);
if(err != QTSS_NoErr)
{
paramLen = sizeof(result);
result = false;
err =QTSS_SetValue(inParams->inRTSPRequest, sAuthenticatedID, 0, (void*)&result, paramLen);
}
return result;
}
inline Bool16 GetRequestFlushState(QTSS_Filter_Params* inParams)
{ Bool16 result = false;
UInt32 paramLen = sizeof(result);
QTSS_Error err = QTSS_GetValue(inParams->inRTSPRequest, sFlushingID, 0, (void*)&result, &paramLen);
if (err != QTSS_NoErr)
{ paramLen = sizeof(result);
result = false;
//qtss_printf("no flush val so set to false session=%"_U32BITARG_" err =%"_S32BITARG_"\n",sSessID, err);
err =QTSS_SetValue(inParams->inRTSPRequest, sFlushingID, 0, (void*)&result, paramLen);
//qtss_printf("QTSS_SetValue flush session=%"_U32BITARG_" err =%"_S32BITARG_"\n",sSessID, err);
}
return result;
}
QTSS_Error FilterRequest(QTSS_Filter_Params* inParams)
{
if (NULL == inParams || NULL == inParams->inRTSPSession || NULL == inParams->inRTSPRequest)
{ Assert(0);
return QTSS_NoErr;
}
OSMutexLocker locker(sAdminMutex);
//check to see if we should handle this request. Invokation is triggered
//by a "GET /" request
QTSS_Error err = QTSS_NoErr;
QTSS_RTSPRequestObject theRequest = inParams->inRTSPRequest;
UInt32 paramLen = sizeof(sSessID);
err = QTSS_GetValue(inParams->inRTSPSession, qtssRTSPSesID, 0, (void*)&sSessID, &paramLen);
if (err != QTSS_NoErr)
return QTSS_NoErr;
StrPtrLen theFullRequest;
err = QTSS_GetValuePtr(theRequest, qtssRTSPReqFullRequest, 0, (void**)&theFullRequest.Ptr, &theFullRequest.Len);
if (err != QTSS_NoErr)
return QTSS_NoErr;
StringParser fullRequest(&theFullRequest);
if ( !IsAdminRequest(&fullRequest) )
return QTSS_NoErr;
if ( !AcceptSession(inParams->inRTSPSession) )
{ (void)QTSS_Write(inParams->inRTSPRequest, sPermissionDeniedHeader, ::strlen(sPermissionDeniedHeader), NULL, 0);
(void)QTSS_Write(inParams->inRTSPRequest, sHTMLBody, ::strlen(sHTMLBody), NULL, 0);
KeepSession(theRequest,false);
return QTSS_NoErr;
}
if(!GetRequestAuthenticatedState(inParams)) // must authenticate before handling
{
if(QTSS_IsGlobalLocked()) // must NOT be global locked
return QTSS_RequestFailed;
if (!IsAuthentic(inParams,&fullRequest))
{
(void)QTSS_Write(inParams->inRTSPRequest, sUnauthorizedResponseHeader, ::strlen(sUnauthorizedResponseHeader), NULL, 0);
(void)QTSS_Write(inParams->inRTSPRequest, sHTMLBody, ::strlen(sHTMLBody), NULL, 0);
KeepSession(theRequest,false);
return QTSS_NoErr;
}
}
if (GetRequestFlushState(inParams))
{ StillFlushing(inParams,true);
return QTSS_NoErr;
}
if (!QTSS_IsGlobalLocked())
{
if (InWaitInterval(inParams))
return QTSS_NoErr;
//qtss_printf("New Request Wait for GlobalLock session=%"_U32BITARG_"\n",sSessID);
(void)QTSS_RequestGlobalLock();
KeepSession(theRequest,true);
return QTSS_NoErr;
}
//qtss_printf("Handle request session=%"_U32BITARG_"\n",sSessID);
APITests_DEBUG();
if (sQueryPtr != NULL)
{ delete sQueryPtr;
sQueryPtr = NULL;
}
sQueryPtr = NEW QueryURI(&theFullRequest);
if (sQueryPtr == NULL) return QTSS_NoErr;
ShowQuery_DEBUG();
if (sAdminPtr != NULL)
{ delete sAdminPtr;
sAdminPtr = NULL;
}
UInt32 result = sQueryPtr->EvalQuery(NULL, NULL);
if (result == 0) do
{
if( ElementNode_CountPtrs() > 0)
{ ElementNode_ShowPtrs();
Assert(0);
}
GetQueryData(theRequest);
SendResult(theRequest);
delete sAdminPtr;
sAdminPtr = NULL;
if (sQueryPtr && !sQueryPtr->QueryHasReponse())
{ UInt32 err = 404;
(void) sQueryPtr->EvalQuery(&err,NULL);
ReportErr(inParams, err);
break;
}
if (sQueryPtr && sQueryPtr->QueryHasReponse())
{ ReportErr(inParams, sQueryPtr->GetEvaluResult());
}
if (sQueryPtr->fIsPref && sQueryPtr->GetEvaluResult() == 0)
{ QTSS_ServiceID id;
(void) QTSS_IDForService(QTSS_REREAD_PREFS_SERVICE, &id);
(void) QTSS_DoService(id, NULL);
}
} while(false);
else
{
SendHeader(theRequest);
ReportErr(inParams, sQueryPtr->GetEvaluResult());
}
if (sQueryPtr != NULL)
{ delete sQueryPtr;
sQueryPtr = NULL;
}
(void) StillFlushing(inParams,true);
return QTSS_NoErr;
}