/* * * @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: QTSSODSAuthModule.cpp Contains: Implementation of QTSSDSAuthModule, a modified version of the AuthenticateRequestModule is sample code. */ #include "QTSSDSAuthModule.h" #include "../../defaultPaths.h" #include "DSAccessChecker.h" #include "StrPtrLen.h" #include "QTSSModuleUtils.h" #include "OSArrayObjectDeleter.h" #include "SafeStdLib.h" #include "QTSSMemoryDeleter.h" #include "QTSS_Private.h" #include "OS.h" //#define SACL 1 #if OSX_SACL extern "C" { #include } #include #include #endif // ATTRIBUTES // STATIC DATA const UInt32 kBuffLen = 512; #define MODPREFIX_ "modDSAuth_" #define AUTHDEBUG 0 #define debug_printf if (AUTHDEBUG) qtss_printf static QTSS_ModulePrefsObject sPrefs = NULL; static QTSS_PrefsObject sServerPrefs = NULL; static OSMutex* sAuthMutex = NULL; static Bool16 sDefaultAuthenticationEnabled = true; static Bool16 sAuthenticationEnabled = true; static char* sDefaultAccessFileName = "qtaccess"; static char* sAccessFileName = NULL; static Bool16 sAllowGuestDefaultEnabled = true; static Bool16 sDefaultGuestEnabled = true; // FUNCTION PROTOTYPES static QTSS_Error QTSSDSAuthModuleDispatch(QTSS_Role inRole, QTSS_RoleParamPtr inParams); static QTSS_Error Register(); static QTSS_Error Initialize(QTSS_Initialize_Params* inParams); static QTSS_Error Shutdown(); static QTSS_Error RereadPrefs(); static QTSS_Error AuthenticateRTSPRequest(QTSS_RTSPAuth_Params* inParams); static QTSS_Error Authorize(QTSS_StandardRTSP_Params* inParams); static Bool16 AuthenticateRequest(QTSS_StandardRTSP_Params* inParams, const char* pathBuff, const char* movieRootDir, StrPtrLen* ioRealmName, Bool16* foundUserPtr); static int check_sacl(const char *inUser); #define kSACLNotAuthorized 0 #define kSACLAuthorized 1 #define kSACLUnknownUser 2 #define kSACLAnyUser 3 // FUNCTION IMPLEMENTATIONS QTSS_Error QTSSDSAuthModule_Main(void* inPrivateArgs) { printf("QTSSDSAuthModule_Main\n"); #if OSX_SACL printf("QTSSDSAuthModule_Main OSX_SACL\n"); #endif #if OSX_OD_API printf("QTSSDSAuthModule_Main OSX_OD_API\n"); #endif return _stublibrary_main(inPrivateArgs, QTSSDSAuthModuleDispatch); } QTSS_Error QTSSDSAuthModuleDispatch(QTSS_Role inRole, QTSS_RoleParamPtr inParams) { switch (inRole) { case QTSS_Register_Role: return Register(); case QTSS_Initialize_Role: return Initialize(&inParams->initParams); case QTSS_RereadPrefs_Role: return RereadPrefs(); case QTSS_RTSPAuthenticate_Role: if (sAuthenticationEnabled) return AuthenticateRTSPRequest(&inParams->rtspAthnParams); case QTSS_RTSPAuthorize_Role: if (sAuthenticationEnabled) return Authorize(&inParams->rtspRequestParams); case QTSS_Shutdown_Role: return Shutdown(); } return QTSS_NoErr; } QTSS_Error Register() { // Do role & attribute setup (void)QTSS_AddRole(QTSS_Initialize_Role); (void)QTSS_AddRole(QTSS_RereadPrefs_Role); (void)QTSS_AddRole(QTSS_RTSPAuthenticate_Role); (void)QTSS_AddRole(QTSS_RTSPAuthorize_Role); return QTSS_NoErr; } QTSS_Error Initialize(QTSS_Initialize_Params* inParams) { // Setup module utils QTSSModuleUtils::Initialize(inParams->inMessages, inParams->inServer, inParams->inErrorLogStream); sPrefs = QTSSModuleUtils::GetModulePrefsObject(inParams->inModule); sServerPrefs = inParams->inPrefs; sAuthMutex = new OSMutex(); RereadPrefs(); return QTSS_NoErr; } QTSS_Error Shutdown() { return QTSS_NoErr; } char* GetCheckedFileName() { char *result = NULL; static char *badChars = "/'\""; char theBadCharMessage[] = "' '"; char *theBadChar = NULL; result = QTSSModuleUtils::GetStringAttribute(sPrefs, MODPREFIX_"dsaccessfilename", sDefaultAccessFileName); StrPtrLen searchStr(result); theBadChar = strpbrk(searchStr.Ptr, badChars); if ( theBadChar!= NULL) { theBadCharMessage[1] = theBadChar[0]; QTSSModuleUtils::LogErrorStr(qtssWarningVerbosity,MODPREFIX_"found invalid DS access file name in prefs"); delete[] result; result = new char[::strlen(sDefaultAccessFileName) + 2]; ::strcpy(result, sDefaultAccessFileName); } return result; } QTSS_Error RereadPrefs() { OSMutexLocker locker(sAuthMutex); QTSSModuleUtils::GetAttribute(sPrefs, MODPREFIX_"enabled", qtssAttrDataTypeBool16, &sAuthenticationEnabled, &sDefaultAuthenticationEnabled, sizeof(sAuthenticationEnabled)); QTSSModuleUtils::GetAttribute(sServerPrefs,"enable_allow_guest_default", qtssAttrDataTypeBool16, &sAllowGuestDefaultEnabled,(void *)&sDefaultGuestEnabled, sizeof(sAllowGuestDefaultEnabled)); delete [] sAccessFileName; sAccessFileName = GetCheckedFileName(); return QTSS_NoErr; } Bool16 AuthenticateRequest(QTSS_StandardRTSP_Params* inParams, const char* pathBuff, const char* movieRootDir, StrPtrLen* ioRealmName, Bool16* foundUserPtr) { if (foundUserPtr) *foundUserPtr = false; if (ioRealmName) //Set Value to Empty for now use whatever is set by access file or the default { ioRealmName->Ptr[0] = '\0'; ioRealmName->Len = 0; } QTSS_Error theErr = QTSS_NoErr; char passwordBuff[kBuffLen]; StrPtrLen passwordStr(passwordBuff, kBuffLen -1); char nameBuff[kBuffLen]; StrPtrLen nameStr(nameBuff, kBuffLen -1); theErr = QTSS_GetValue (inParams->inRTSPRequest,qtssRTSPReqUserName,0, (void *) nameStr.Ptr, &nameStr.Len); if ( (QTSS_NoErr != theErr) || (nameStr.Len >= kBuffLen) ) { debug_printf("QTSSDSAuthModule:AuthenticateRequest() Username Error - %"_S32BITARG_"\n", theErr); return false; } theErr = QTSS_GetValue (inParams->inRTSPRequest,qtssRTSPReqUserPassword,0, (void *) passwordStr.Ptr, &passwordStr.Len); if ( (QTSS_NoErr != theErr) || (passwordStr.Len >= kBuffLen) ) { debug_printf("QTSSDSAuthModule:AuthenticateRequest() Password Error - %"_S32BITARG_"\n", theErr); return false; } nameBuff[nameStr.Len] = '\0'; passwordBuff[passwordStr.Len] = '\0'; // // Use the name and password to check access DSAccessChecker accessChecker; if ( !accessChecker.CheckPassword( nameBuff, passwordBuff) ) { return false; } if (foundUserPtr) *foundUserPtr = true; return true; } QTSS_Error AuthenticateRTSPRequest(QTSS_RTSPAuth_Params* inParams) { OSMutexLocker locker(sAuthMutex); QTSS_RTSPRequestObject theRTSPRequest = inParams->inRTSPRequest; QTSS_AuthScheme authScheme = qtssAuthNone; debug_printf("QTSSDSAuthModule:AuthenticateRTSPRequest start\n"); if ( (NULL == inParams) || (NULL == inParams->inRTSPRequest) ) { debug_printf("QTSSDSAuthModule:AuthenticateRTSPRequest inParams NULL\n"); return QTSS_RequestFailed; } // Get the user profile object from the request object QTSS_UserProfileObject theUserProfile = NULL; UInt32 len = sizeof(QTSS_UserProfileObject); QTSS_Error theErr = QTSS_GetValue(theRTSPRequest, qtssRTSPReqUserProfile, 0, (void*)&theUserProfile, &len); Assert(len == sizeof(QTSS_UserProfileObject)); if (theErr != QTSS_NoErr) { debug_printf("QTSSDSAuthModule:AuthenticateRTSPRequest - username error is %"_S32BITARG_"\n", theErr); return theErr; } char* nameBuff = NULL; theErr = QTSS_GetValueAsString(theUserProfile, qtssUserName, 0, &nameBuff); debug_printf("QTSSDSAuthModule:AuthenticateRTSPRequest - username is %s\n", nameBuff); OSCharArrayDeleter usernameBufDeleter(nameBuff); if (theErr != QTSS_NoErr) { debug_printf("QTSSDSAuthModule:AuthenticateRTSPRequest - theUserProfile nameBuff error is %"_S32BITARG_"\n", theErr); } len = sizeof(authScheme); theErr = QTSS_GetValue(theRTSPRequest, qtssRTSPReqAuthScheme, 0, (void*)&authScheme, &len); if (theErr != QTSS_NoErr) return theErr; DSAccessChecker accessChecker; Bool16 allowed = true; Bool16 foundUser = true; Bool16 authHandled = true; if ( authScheme == qtssAuthDigest) { debug_printf("QTSSDSAuthModule:AuthenticateRTSPRequest - authScheme = qtssAuthDigest\n"); char* challengeBuff = NULL; (void) QTSS_GetValueAsString(theRTSPRequest, qtssRTSPReqDigestChallenge, 0, &challengeBuff); OSCharArrayDeleter challengeDeleter(challengeBuff); debug_printf("QTSSDSAuthModule:AuthenticateRTSPRequest - Server Challenge =%s\n",challengeBuff); char* responseBuff = NULL; (void) QTSS_GetValueAsString(theRTSPRequest, qtssRTSPReqDigestResponse, 0, &responseBuff); OSCharArrayDeleter responseDeleter(responseBuff); char* methodBuff = NULL; (void) QTSS_GetValueAsString(theRTSPRequest, qtssRTSPReqMethodStr, 0, &methodBuff); OSCharArrayDeleter methodDeleter(methodBuff); debug_printf("QTSSDSAuthModule:AuthenticateRTSPRequest - Server Method =%s\n",methodBuff); debug_printf("QTSSDSAuthModule:AuthenticateRTSPRequest - username is %s challenge=%s response=%s method=%s\n", nameBuff, challengeBuff, responseBuff, methodBuff); if ( false == accessChecker.CheckDigest(nameBuff, challengeBuff, responseBuff, methodBuff) ) { debug_printf("QTSSDSAuthModule CheckDigest returned false\n"); } else { debug_printf("QTSSDSAuthModule CheckDigest returned true\n"); (void) QTSSModuleUtils::AuthorizeRequest(theRTSPRequest,&allowed,&foundUser,&authHandled); } } if ( authScheme == qtssAuthBasic) { debug_printf("QTSSDSAuthModule:AuthenticateRTSPRequest - authScheme = qtssAuthBasic\n"); char passwordBuff[kBuffLen]; StrPtrLen passwordStr(passwordBuff, kBuffLen -1); char nameBuff[kBuffLen]; StrPtrLen nameStr(nameBuff, kBuffLen -1); theErr = QTSS_GetValue (inParams->inRTSPRequest,qtssRTSPReqUserName,0, (void *) nameStr.Ptr, &nameStr.Len); if ( (QTSS_NoErr != theErr) || (nameStr.Len >= kBuffLen) ) { debug_printf("QTSSDSAuthModule:AuthenticateRequest() Username Error - %"_S32BITARG_"\n", theErr); return false; } theErr = QTSS_GetValue (inParams->inRTSPRequest,qtssRTSPReqUserPassword,0, (void *) passwordStr.Ptr, &passwordStr.Len); if ( (QTSS_NoErr != theErr) || (passwordStr.Len >= kBuffLen) ) { debug_printf("QTSSDSAuthModule:AuthenticateRequest() Password Error - %"_S32BITARG_"\n", theErr); } nameBuff[nameStr.Len] = '\0'; passwordBuff[passwordStr.Len] = '\0'; debug_printf("QTSSDSAuthModule:AuthenticateRTSPRequest - username is %s\n", nameBuff); debug_printf("QTSSDSAuthModule:AuthenticateRTSPRequest - password is %s\n", passwordBuff); if ( !accessChecker.CheckPassword(nameBuff, passwordBuff) ) { debug_printf("QTSSDSAuthModule CheckPassword returned false\n"); } else { debug_printf("QTSSDSAuthModule CheckPassword returned true\n"); (void) QTSSModuleUtils::AuthorizeRequest(theRTSPRequest,&allowed,&foundUser,&authHandled); } } return QTSS_NoErr; } int check_sacl(const char *inUser) { #if OSX_SACL int mbrErr = ENOENT; int isMember = 0; uuid_t user_uuid; uuid_t uu; mbrErr = mbr_uid_to_uuid(geteuid(), uu); if (0 == mbrErr) { mbrErr = mbr_check_service_membership(uu, "qtss", &isMember); if (ENOENT == mbrErr) //no acl exists so allow any user. return kSACLAnyUser; } if( (mbrErr = mbr_user_name_to_uuid(inUser, user_uuid)) != 0) { return kSACLUnknownUser; } if((mbrErr = mbr_check_service_membership(user_uuid, "qtss", &isMember)) != 0) { if(mbrErr == ENOENT){ // no ACL exists return kSACLAuthorized; } else { return kSACLNotAuthorized; } } if(isMember == kSACLAuthorized) { return kSACLAuthorized; } return kSACLNotAuthorized; #else return kSACLAuthorized; #endif } QTSS_Error Authorize(QTSS_StandardRTSP_Params* inParams) { OSMutexLocker locker(sAuthMutex); QTSS_RTSPRequestObject theRTSPRequest = inParams->inRTSPRequest; if ( (NULL == inParams) || (NULL == inParams->inRTSPRequest) ) { debug_printf("QTSSDSAuthModule - Authorize inParams: Error"); return QTSS_RequestFailed; } //get the local file path char* pathBuffStr = NULL; QTSS_Error theErr = QTSS_GetValueAsString(theRTSPRequest, qtssRTSPReqLocalPath, 0, &pathBuffStr); QTSSCharArrayDeleter pathBuffDeleter(pathBuffStr); if (theErr != QTSS_NoErr) { debug_printf("QTSSDSAuthModule - Authorize [QTSS_GetValueAsString]: Error %"_S32BITARG_"", theErr); return QTSS_RequestFailed; } //get the root movie directory char* movieRootDirStr = NULL; theErr = QTSS_GetValueAsString(theRTSPRequest,qtssRTSPReqRootDir, 0, &movieRootDirStr); OSCharArrayDeleter movieRootDeleter(movieRootDirStr); if (theErr != QTSS_NoErr) { debug_printf("QTSSDSAuthModule - Authorize[QTSS_GetValueAsString]: Error %"_S32BITARG_"", theErr); return false; } //check if this user is allowed to see this movie DSAccessFile accessFile; Bool16 allowNoAccessFiles = sAllowGuestDefaultEnabled; //no access files allowed means allowing guest access (unknown users) Bool16 allowAnyUser = false; QTSS_ActionFlags noAction = ~qtssActionFlagsRead; //only handle read QTSS_ActionFlags authorizeAction = QTSSModuleUtils::GetRequestActions(theRTSPRequest); Bool16 authorized =false; Bool16 saclUser = false; char *name = NULL; (void) QTSS_GetValueAsString (theRTSPRequest,qtssRTSPReqUserName,0, &name); OSCharArrayDeleter nameDeleter(name); if (sAllowGuestDefaultEnabled) // if guest access is on, sacls are ignored. { authorized = true; } else { int result = check_sacl(name); switch (result) { case kSACLAuthorized: authorized = true; break; case kSACLUnknownUser: authorized = false; //set this to true to allow file based and other non-directory service users access, when SACLs are enabled in the system for QTSS. break; case kSACLNotAuthorized: authorized = false; break; case kSACLAnyUser: authorized = true; break; default: authorized = false; } debug_printf("QTSSDSAuthModule:Authorize sacl_check result=%d for %s authorized = %d\n",result, name, authorized); if (false == authorized) saclUser = true; } Bool16 foundUser = false; Bool16 passwordOK = false; //::AuthenticateRequest(inParams, pathBuffStr, movieRootDirStr, &sRealmNameStr, &foundUser); if (authorized) //have to be authorized by sacls or guest first before qtaccess file checks can allow or disallow. { theErr = accessFile.AuthorizeRequest(inParams,allowNoAccessFiles, noAction, authorizeAction,&authorized, &allowAnyUser); debug_printf("QTSSDSAuthModule:Authorize AuthorizeRequest() returned authorized=%d allowAnyUser=%d\n", authorized, allowAnyUser); } debug_printf("QTSSDSAuthModule:Authorize AuthenticateRequest() returned passwordOK=%d foundUser=%d authorized=%d allowAnyUser=%d\n", passwordOK ,foundUser, authorized,allowAnyUser); Bool16 allowRequest = authorized; Bool16 authHandled = true; if(!(authorizeAction & qtssActionFlagsRead)) //not for us { debug_printf("QTSSDSAuthModule:Authorize(qtssActionFlagsRead) not handled do nothing.\n"); } else if (allowRequest) { debug_printf("QTSSDSAuthModule:Authorize() succeeded.\n"); theErr = QTSSModuleUtils::AuthorizeRequest(theRTSPRequest, &allowRequest, &foundUser, &authHandled); debug_printf("QTSSDSAuthModule:Authorize allowRequest=%d founduser=%d authHandled=%d\n", allowRequest, foundUser, authHandled); } else //request denied { debug_printf("QTSSDSAuthModule:Authorize() failed.\n"); foundUser = saclUser; authHandled = true; theErr = QTSSModuleUtils::AuthorizeRequest(theRTSPRequest, &allowRequest, &foundUser, &authHandled); debug_printf("QTSSDSAuthModule:Authorize allowRequest=%d founduser=%d authHandled=%d saclUser=%d\n", allowRequest, foundUser, authHandled,saclUser); } return theErr; }