#!/usr/bin/perl # # @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@ # require('tag_vals.pl'); require('tag_types.pl'); require('tag_formats.pl'); require('adminprotocol-lib.pl'); require('cgi-lib.pl'); require('playlist-lib.pl'); require('relayxmlparser.pl'); require('password-utils.pl'); # Get the server name, QTSS IP address, and Port from ENV hash $servername = $ENV{"SERVER_SOFTWARE"}; $qtssip = $ENV{"QTSSADMINSERVER_QTSSIP"}; $qtssport = $ENV{"QTSSADMINSERVER_QTSSPORT"}; $remoteip = $ENV{"REMOTE_HOST"}; $accessdir = $ENV{"LANGDIR"}; $nonAuthenticatedActions = ("|login|logout|AssistSetPassword|"); $displayedLoginMessage = 0; $auth = ''; $authheader = ''; $messageHash = &adminprotolib::GetMessageHash(); $cookie = ''; $password = ''; $iteration = ''; $cookieExpireSecs = $ENV{"COOKIE_EXPIRE_SECONDS"}; # this array will get filled by the foundTag function my %endTags = (); # tag depth variable my $tag_depth = 0; sub encodeBase64 { my $res = ''; pos($_[0]) = 0; # ensure start at the beginning while ($_[0] =~ /(.{1,45})/gs) { $res .= substr(pack('u', $1), 1); chop($res); } $res =~ tr|` -_|AA-Za-z0-9+/|; # `# help emacs # fix padding at the end my $padding = (3 - length($_[0]) % 3) % 3; $res =~ s/.{$padding}$/'=' x $padding/e if $padding; return $res; } # b64decode(string) # Converts a string from base64 format to normal sub b64decode { local($str) = $_[0]; local($res); $str =~ tr|A-Za-z0-9+=/||cd; $str =~ s/=+$//; $str =~ tr|A-Za-z0-9+/| -_|; while ($str =~ /(.{1,60})/gs) { my $len = chr(32 + length($1)*3/4); $res .= unpack("u", $len . $1 ); } return $res; } sub repeaterExists { my $testRepeater = $_[0]; my $i = 0; my $foundItem = ''; my $currentItem = ''; foreach $theItem (@returnedKeys) { if ($theItem eq $testRepeater) { $foundItem = 1; last; } } return $foundItem; } sub addIterationAttribute { my $tagAttributes = $_[0]; my $endTagSlash = $_[1]; my $singleTagSlash = $_[2]; my $iterationNumber = $_[3]; if ($endTagSlash eq '/') { return ''; } else { return ''; } } # this routine, erm, expands repeater tags. Adds an iteration attribute to all contained qtssobject tags. sub expandRepeater { my $tagAttributes = $_[0]; my $tagContents = $_[1]; my $name = ''; my $arraySize = 0; my $currentIteration = 0; my $returnedText = ''; $_ = $tagAttributes; if (/ name="[^"]*"| name=[^ (\/>)]*/si) { $name = $&; $name =~ s/ *name="*//; $name =~ s/"//; } $arraySize = getRepeaterArray($name); # return '@' . $returnedKeys[0]; # $arraySize = scalar(eval('@' . $returnedKeys[0])); for ($currentIteration = 0; $currentIteration < $arraySize; $currentIteration++) { $_ = $tagContents; s{ < ( /*? ) qtssobject ( .*? ) (/*?) >} { addIterationAttribute($2, $1, $3, $currentIteration) }isgxe; $returnedText .= $_; } return $returnedText; } # this routine takes the contents of a qtssobject tag and deals with it accordingly sub foundTag { my $data = ''; my $tagAttributes = $_[0]; my $endTagSlash = $_[1]; my $singleTagSlash = $_[2]; my $name = ''; my $type = ''; my $value = ''; my $format = ''; my $userParam = ''; my $final_value = ''; $iteration = ''; $_ = $tagAttributes; if ($endTagSlash eq "/") { $final_value = $endTags{$tag_depth}; $tag_depth--; return $final_value; } if (/ name="[^"]*"| name=[^ (\/>)]*/si) { $name = $&; $name =~ s/ *name="*//; $name =~ s/"//; } if (/ type="[^"]*"| type=[^ (\/>)]*/si) { $type = $&; $type =~ s/ *type="*//; $type =~ s/"//; } else { $type = $defaultTypes{$name}; } if (/ iteration="[^"]*"| iteration=[^ (\/>)]*/si) { $iteration = $&; $iteration =~ s/ *iteration="*//; $iteration =~ s/"//; } # get the end tag, if necessary if ($singleTagSlash eq '') { $tag_depth++; $endTags{$tag_depth} = $endTagTypes{$type}; } if (/ format="[^"]*"| format=[^ (\/>)]*/si) { $format = $&; $format =~ s/ *format="*//; $format =~ s/"//; } else { $format = $defaultFormats{$name}; } if (/ param="[^"]*"| param=[^ (\/>)]*/si) { $userParam = $&; $userParam =~ s/ *param="*//; $userParam =~ s/"//; } else { $userParam = ''; } $value = $tagVals{$name}; #check to see if there's an iteration #if so, check to see if a repeater with this name exists if ($iteration ne '') { # return $name; if (repeaterExists($name)) { $value = eval('$' . $name . "[$iteration]"); $name .= $iteration; } } $_ = $value; #if it starts with / then we'll assume it's a path to a server var if (($_ ne '') && (/^\//) && ($iteration eq '')) { my $messHash = adminprotolib::GetMessageHash(); $status = adminprotolib::EchoData($data, $messHash, $authheader, $qtssip, $qtssport, $value, $value); if (($status == 500) and ($data =~ /Connection refused/) and ($displayedLoginMessage == 0)) { $displayedLoginMessage = 1; $wasAuth = 0; my $loginText = ''; open(LOGINFILE, "start_server.html") or die "Can't open server start file!"; while ($line = ) { $loginText .= $line; } close(LOGINFILE); $loginText = parseTags($loginText); &cgilib::PrintOKTextHeader($servername); print $loginText; return 0; } if ($status == 401) { my $isAuthenticated = 0; if ($wasAuth == (-1)) { $value = ''; return ''; } # only try default authentication if setup assistant on mac os x if (($^O eq "darwin") and (-e "index.html") and ($ENV{"REMOTE_HOST"} eq '127.0.0.1') and (MacQTGroupsContainsAdminGroup() == 0)) { if (wasAuth >= 0) { # first pass open(LOGINFILE, "setup_assistant.html"); my $loginText = ''; while ($line = ) { $loginText .= $line; } close(LOGINFILE); $wasAuth = (-1); $loginText = parseTags($loginText); &cgilib::PrintOKTextHeader($servername); print $loginText; return 0; } } if (($displayedLoginMessage == 0) && ($isAuthenticated == 0)) { $displayedLoginMessage = 1; # now using cookies to store password; return login page my $loginText = ''; open(LOGINFILE, "login.html") or die "Can't open login file!"; while ($line = ) { $loginText .= $line; } close(LOGINFILE); $loginText = parseTags($loginText); &cgilib::PrintOKTextHeader($servername); print $loginText; $wasAuth = 0; return 0; } } $value = $data; } # if it starts with = then we'll evaluate it, replacing stuff first # small possibility for nasty recursion exists here # be sure not to include another evaluating tag inside this one $_ = $value; if (/^=/) { $value =~ s/^=//; $value = parseTags($value); $value = eval($value); } # format value $value = runFormatter($value, $format, $userParam, $name); $final_value = $tagTypes{$type}; if ($final_value eq '') { $final_value = $tagTypes{'plaintext'}; } $final_value =~ s//$value/gi; $final_value =~ s//$name/gi; $final_value =~ s//$userParam/gi; $final_value =~ s//$filename/gi; $_ = $final_value; return $final_value; } #this routine replaces localized strings from the messages file sub foundString { my $tagAttributes = $_[0]; my $endTagSlash = $_[1]; my $singleTagSlash = $_[2]; my $name = ''; $_ = $tagAttributes; if (/ name="[^"]*"| name=[^ (\/>)]*/si) { $name = $&; $name =~ s/ *name="*//; $name =~ s/"//; } my $messHash = adminprotolib::GetMessageHash(); my %messages = %$messHash; my $QTName = 'QT' . $name; if (($^O eq "darwin") and ($messages{$QTName} ne '')) { return $messages{$QTName}; } return "$messages{$name}"; } #this routine calls foundTag for each tag found. sub parseTags { $_[0] =~ s{ ( .*?) } { expandRepeater($1, $2) }isgxe; $_[0] =~ s{ < ( /*? ) qtssobject ( .*? ) (/*?) >} { foundTag($2, $1, $3) }isgxe; $_[0] =~ s{ < ( /*? ) qtssstring ( .*? ) (/*?) >} { foundString($2, $1, $3) }isgxe; return "$_[0]"; } sub StartStopServer { my $messageHash = &adminprotolib::GetMessageHash(); my $data = ""; my $status = &adminprotolib::EchoData($data, $messageHash, $authheader, $qtssip, $qtssport, "/modules/admin/server/qtssSvrState", "/server/qtssSvrState"); # if the server is not running, launch process if($status == 200) { # if server is running, then put it in idle mode or if server is idle/not running, then put it in running mode if($data == 1) { $status = &adminprotolib::SetAttribute($data, $messageHash, $authheader, $qtssip, $qtssport, "/admin/server/qtssSvrState", 5); } else { $status = &adminprotolib::SetAttribute($data, $messageHash, $authheader, $qtssip, $qtssport, "/admin/server/qtssSvrState", 1); } } } sub SaveGeneralSettings { my $messHash = adminprotolib::GetMessageHash(); my %messages = %$messHash; my $settingsPath = '/admin/server/qtssSvrPreferences/'; my $data = ''; my $configFilePath = $ENV{"QTSSADMINSERVER_CONFIG"}; my $sslValue = $query->{'adminSSL'}; my $autoStartValue = $query->{'qtssExtraGenSettings0'}; my $name = ''; my $val = ''; if ($sslValue ne '1') { $sslValue = '0'; } if ($autoStartValue ne '1') { $autoStartValue = '0'; } if ($query->{'qtssMovieFolder'} ne $query->{'qtssMovieFolder_shadow'}) { $status = &adminprotolib::SetAttribute($data, $messHash, $authheader, $qtssip, $qtssport, $settingsPath."movie_folder", $query->{'qtssMovieFolder'}); } if ($query->{'qtssMaxConn'} ne $query->{'qtssMaxConn_shadow'}) { $status = &adminprotolib::SetAttribute($data, $messHash, $authheader, $qtssip, $qtssport, $settingsPath."maximum_connections", $query->{'qtssMaxConn'}); } if (($query->{'bpsinput'} ne $query->{'bpsinput_shadow'}) or ($query->{'kbpstype'} ne $query->{'kbpstype_shadow'})) { my $amt = $query->{'bpsinput'}; if ($query->{'kbpstype'} eq 'mbps') { $amt = $amt * 1024 } $status = &adminprotolib::SetAttribute($data, $messHash, $authheader, $qtssip, $qtssport, $settingsPath."maximum_bandwidth", $amt); } if ($query->{'qtssAuthScheme'} ne $query->{'qtssAuthScheme_shadow'}) { $status = &adminprotolib::SetAttribute($data, $messHash, $authheader, $qtssip, $qtssport, $settingsPath."authentication_scheme", $query->{'qtssAuthScheme'}); } if ($sslValue ne parseForSSL()) { $configLine = qq(ssl=$sslValue\n); if(!(-e $configFilePath)) { open(CONFIGFILE, ">$configFilePath"); print CONFIGFILE $configLine; close(CONFIGFILE); FixFileGroup($configFilePath); if($sslValue == 1) { $ENV{"HTTPS"} = "ON"; } else { $ENV{"HTTPS"} = "OFF"; } } else { if( -r $configFilePath && -w _) { $tmpname = $configFilePath . ".tmp"; open(TEMPFILE, ">$tmpname"); open(CONFIGFILE, "<$configFilePath"); while($line = ) { $_ = $line; chop; if (/^#/ || !/\S/) { print TEMPFILE $line; next; } /^([^=]+)=(.*)$/; $name = $1; $val = $2; $name =~ s/^\s+//g; $name =~ s/\s+$//g; $val =~ s/^\s+//g; $val =~ s/\s+$//g; if($name eq "ssl") { $val = $sslValue; } $config{$name} = $val; print TEMPFILE qq($name=$val\n); } if(!defined($config{'ssl'})) { print TEMPFILE $configLine; } close(CONFIGFILE); close(TEMPFILE); rename $tmpname, $configFilePath; if($sslValue == 1) { $ENV{"HTTPS"} = "ON"; } else { $ENV{"HTTPS"} = "OFF"; } } else { print STDERR "couldn't open $configFilePath for writing\n"; } } } $confirmMessage = $messages{'GenSetSettingsSavedText'}; } sub RunAssistant { my $messHash = adminprotolib::GetMessageHash(); my %messages = %$messHash; my $settingsPath = '/admin/server/qtssSvrPreferences/'; my $MP3BroadcastPasswordPath = "/admin/server/qtssSvrModuleObjects/QTSSMP3StreamingModule/qtssModPrefs/mp3_broadcast_password"; my $data = ''; my $configFilePath = $ENV{"QTSSADMINSERVER_CONFIG"}; my $sslValue = $query->{'assistSSL'}; my $name = ''; my $val = ''; if ($sslValue ne '1') { $sslValue = '0'; } # set MP3 Broadcast Password $status = &adminprotolib::SetAttribute($data, $messHash, $authheader, $qtssip, $qtssport, $MP3BroadcastPasswordPath, $query->{'assistMP3Pass'}); # set media folder $status = &adminprotolib::SetAttribute($data, $messHash, $authheader, $qtssip, $qtssport, $settingsPath."movie_folder", $query->{'assistMovieFolder'}); # set streaming on port 80 SavePortSettings(); $confirmMessage = ''; # reset the confirm message # set SSL on/off $configLine = qq(ssl=$sslValue\n); if(!(-e $configFilePath)) { open(CONFIGFILE, ">$configFilePath"); print CONFIGFILE $configLine; close(CONFIGFILE); FixFileGroup($configFilePath); if($sslValue == 1) { $ENV{"HTTPS"} = "ON"; } else { $ENV{"HTTPS"} = "OFF"; } } else { if( -r $configFilePath && -w _) { $tmpname = $configFilePath . ".tmp"; open(TEMPFILE, ">$tmpname"); open(CONFIGFILE, "<$configFilePath"); while($line = ) { $_ = $line; chop; if (/^#/ || !/\S/) { print TEMPFILE $line; next; } /^([^=]+)=(.*)$/; $name = $1; $val = $2; $name =~ s/^\s+//g; $name =~ s/\s+$//g; $val =~ s/^\s+//g; $val =~ s/\s+$//g; if($name eq "ssl") { $val = $sslValue; } $config{$name} = $val; print TEMPFILE qq($name=$val\n); } if(!defined($config{'ssl'})) { print TEMPFILE $configLine; } close(CONFIGFILE); close(TEMPFILE); rename $tmpname, $configFilePath; if($sslValue == 1) { $ENV{"HTTPS"} = "ON"; } else { $ENV{"HTTPS"} = "OFF"; } } else { print STDERR "couldn't open $configFilePath for writing\n"; } } } sub SavePortSettings { my $messHash = adminprotolib::GetMessageHash(); my %messages = %$messHash; my $data = ''; my $settingsPath = '/admin/server/qtssSvrPreferences/'; if ($query->{'qtssIsStreamingOn80'} ne $query->{'qtssIsStreamingOn80_shadow'}) { if($query->{'qtssIsStreamingOn80'} eq "true") { # set the pref $status = &adminprotolib::AddValueToAttribute($data, $messHash, $authheader, $qtssip, $qtssport, $settingsPath."rtsp_port", 80); # find out where the pid file is my $pidfileloc = ''; my $status = &adminprotolib::EchoData($pidfileloc, $messageHash, $authheader, $qtssip, $qtssport, "/modules/admin/server/qtssSvrPreferences/pid_file", "/server/qtssSvrPreferences/pid_file"); # if the pid file exists... if (-e $pidfileloc) { # read in the file into an array my @splitPidFile = (); my $line; if (open(PIDFILE, $pidfileloc)) { while ($line = ) { push(@splitPidFile, $line); } close(PIDFILE); } if (scalar(@splitPidFile) > 0) { if ($splitPidFile[1] ne '') { kill 2, $splitPidFile[1]; sleep(2); } } } } else { $status = &adminprotolib::DeleteValueFromAttribute($data, $messHash, $authheader, $qtssip, $qtssport, $settingsPath."rtsp_port", 80); } } $confirmMessage = $messages{'PortSetSavedText'}; } sub SaveLogSettings { my $messHash = adminprotolib::GetMessageHash(); my %messages = %$messHash; my $errorPath = "/admin/server/qtssSvrPreferences/"; my $accessPath = "/admin/server/qtssSvrModuleObjects/QTSSAccessLogModule/qtssModPrefs/"; my $data = ''; $nextFilename = 'log_settings.html'; if ($query->{'qtssErrorLogging'} ne $query->{'qtssErrorLogging_shadow'}) { if ($query->{'qtssErrorLogging'} eq 'true') { $status = &adminprotolib::SetAttribute($data, $messHash, $authheader, $qtssip, $qtssport, $errorPath."error_logging", true); } else { $status = &adminprotolib::SetAttribute($data, $messHash, $authheader, $qtssip, $qtssport, $errorPath."error_logging", false); } } if ($query->{'qtssErrorLogInterval'} ne $query->{'qtssErrorLogInterval_shadow'}) { $status = &adminprotolib::SetAttribute($data, $messHash, $authheader, $qtssip, $qtssport, $errorPath."error_logfile_interval", $query->{'qtssErrorLogInterval'}); } if ($query->{'qtssErrorLogSize'} ne $query->{'qtssErrorLogSize_shadow'}) { $status = &adminprotolib::SetAttribute($data, $messageHash, $authheader, $qtssip, $qtssport, $errorPath."error_logfile_size", ($query->{'qtssErrorLogSize'} * 1024)); } if ($query->{'qtssRequestLogging'} ne $query->{'qtssRequestLogging_shadow'}) { if ($query->{'qtssRequestLogging'} eq 'true') { $status = &adminprotolib::SetAttribute($data, $messHash, $authheader, $qtssip, $qtssport, $accessPath."request_logging", true); } else { $status = &adminprotolib::SetAttribute($data, $messHash, $authheader, $qtssip, $qtssport, $accessPath."request_logging", false); } } if ($query->{'qtssRequestLogInterval'} ne $query->{'qtssRequestLogInterval_shadow'}) { $status = &adminprotolib::SetAttribute($data, $messHash, $authheader, $qtssip, $qtssport, $accessPath."request_logfile_interval", $query->{'qtssRequestLogInterval'}); } if ($query->{'qtssRequestLogSize'} ne $query->{'qtssRequestLogSize_shadow'}) { $status = &adminprotolib::SetAttribute($data, $messageHash, $authheader, $qtssip, $qtssport, $accessPath."request_logfile_size", ($query->{'qtssRequestLogSize'} * 1024)); } $filename = 'log_settings.html'; $confirmMessage = $messages{'LogSetSavedText'}; } sub ChangePassword { my $messHash = adminprotolib::GetMessageHash(); my %messages = %$messHash; my $usersFileAttributePath = "/server/qtssSvrModuleObjects/QTSSAccessModule/qtssModPrefs/modAccess_usersfilepath"; my $groupsFileAttributePath = "/server/qtssSvrModuleObjects/QTSSAccessModule/qtssModPrefs/modAccess_groupsfilepath"; my $usersFilePath = ''; my $groupsFilePath = ''; my $qtssPasswdName = $ENV{"QTSSADMINSERVER_QTSSQTPASSWD"}; my $data = ''; my $line = ''; my $oldUsername = $query->{'old_username'}; my $newUsername = $query->{'new_user'}; my $groupsFileText = ''; my $usersFileText = ''; $nextFilename = 'change_password.html'; # if username or password is blank if (($query->{'new_user'} eq '') or ($query->{'new_password1'} eq '')) { $dialogHeader = $messages{'SetupAssistNoUsernameHeader'}; $dialogText = $messages{'SetupAssistNoUsername'}; return; } # if username has more than 255 characters if (length($query->{'new_user'}) > 255) { $dialogHeader = $messages{'ChPassUsernameNotLongerThan255Header'}; $dialogText = $messages{'ChPassUsernameNotLongerThan255Text'}; return; } # if username has a colon if ($query->{'new_user'} =~ /:/) { $dialogHeader = $messages{'ChPassUsernameCannotHaveColonHeader'}; $dialogText = $messages{'ChPassUsernameCannotHaveColonText'}; return; } # if username or password has a single or a double quote if ( ($query->{'new_user'} =~ /['"]/) || ($query->{'new_password1'} =~ /['"]/) ) { $dialogHeader = $messages{'ChPassCannotHaveQuotesHeader'}; $dialogText = $messages{'ChPassCannotHaveQuotesText'}; return; } # if password has more than 80 characters if (length($query->{'new_password1'}) > 80) { $dialogHeader = $messages{'ChPassNotLongerThan80Header'}; $dialogText = $messages{'ChPassNotLongerThan80Text'}; return; } # if old username:password doesn't match the current username:password if (encodeBase64($oldUsername.':'.$query->{'old_password'}) ne getCookie('qtsspassword')) { $dialogHeader = $messages{'ChPassOldPasswdWrongHeader'}; $dialogText = $messages{'ChPassOldPasswdWrongText'}; return; } # if new password #1 and new password #2 don't match if ($query->{'new_password1'} ne $query->{'new_password2'}) { $dialogHeader = $messages{'ChPassNoMatchHeader'}; $dialogText = $messages{'ChPassNoMatchText'}; return; } my $status = &adminprotolib::EchoData($groupsFilePath, $messHash, $authheader, $qtssip, $qtssport, "/modules/admin$groupsFileAttributePath", "/modules/admin$groupsFileAttributePath"); if ($status != 200) { $dialogHeader = $messages{'ChPassErrorHeader'}; $dialogText = $messages{'ChPassErrorText'}." ($status - $data)"; return; } $status = &adminprotolib::EchoData($usersFilePath, $messHash, $authheader, $qtssip, $qtssport, "/modules/admin$usersFileAttributePath", "/modules/admin$usersFileAttributePath"); if ($status != 200) { $dialogHeader = $messages{'ChPassErrorHeader'}; $dialogText = $messages{'ChPassErrorText'}." ($status - $data)"; return; } open(FILEHDL, "$groupsFilePath") or die "Can't open groups file '$groupsFilePath'!"; while ($line = ) { $groupsFileText .= $line; } close(FILEHDL); my $quotedOldUsername = quotemeta($oldUsername); $groupsFileText =~ s/([ \t:]+)$quotedOldUsername([\r\n\s]+)/$1$newUsername$2/; $status = &adminprotolib::SetPassword($data, $messageHash, $authheader, $qtssip, $qtssport, $usersFileAttributePath, $query->{'new_password1'}, $qtssPasswdName, $newUsername); sleep(2); if ($status != 200) { $dialogHeader = $messages{'ChPassErrorHeader'}; $dialogText = $messages{'ChPassErrorText'}." ($status - $data)"; return; } open(FILEHDL, ">$groupsFilePath") or die "Can't open groups file '$groupsFilePath'!"; print FILEHDL $groupsFileText; close(FILEHDL); FixFileGroup($groupsFilePath); $newcookieval = encodeBase64($newUsername.':'.$query->{'new_password1'}); $cookie = 'qtsspassword='.$newcookieval.';path=/'; $auth = $newcookieval; $authheader = "Authorization: Basic $auth\r\n"; if ($oldUsername ne $newUsername) { &adminprotolib::DeleteUsername($data, $messageHash, $authheader, $qtssip, $qtssport, $usersFileAttributePath, $qtssPasswdName, $oldUsername); } # $confirmMessage = $messages{'ChPassSavedText'}; $filename = 'change_password_redirect.html'; } sub ChangeBroadcastPassword { my $messHash = adminprotolib::GetMessageHash(); my %messages = %$messHash; my $filedelim = &playlistlib::GetFileDelimChar(); my $moviesFolderPath; my $status = &adminprotolib::EchoData($moviesFolderPath, $messHash, $authheader, $qtssip, $qtssport, "/modules/admin/server/qtssSvrPreferences/movie_folder", "movie_folder"); my $accessFilename; $status = &adminprotolib::EchoData($accessFilename, $messHash, $authheader, $qtssip, $qtssport, "/modules/admin/server/qtssSvrModuleObjects/QTSSAccessModule/qtssModPrefs/modAccess_qtaccessfilename", "modAccess_qtaccessfilename"); my $usersFilename; $status = &adminprotolib::EchoData($usersFilename, $messHash, $authheader, $qtssip, $qtssport, "/modules/admin/server/qtssSvrModuleObjects/QTSSAccessModule/qtssModPrefs/modAccess_usersfilepath", "modAccess_usersfilepath"); my $groupsFilename; $status = &adminprotolib::EchoData($groupsFilename, $messHash, $authheader, $qtssip, $qtssport, "/modules/admin/server/qtssSvrModuleObjects/QTSSAccessModule/qtssModPrefs/modAccess_groupsfilepath", "modAccess_groupsfilepath"); $moviesFolderPath =~ s/[\/\\]$//o; my $filename = "$moviesFolderPath$filedelim$accessFilename"; my $viewingUsersArrayRef = &passwordutils::GetViewingRestrictionsFromFile($filename); my @viewingUsersArray = @$viewingUsersArrayRef; my $viewingUsersString = join(' ', @viewingUsersArray); my $broadcastUsersArrayRef = &passwordutils::GetBroadcastRestrictionsFromFile($filename); my @broadcastUsersArray = @$broadcastUsersArrayRef; my $oldBroadcastUser = ''; my $broadcastRestrictionString = ''; my ($currentAdminUsername, $currentAdminPass) = split(/:/, b64decode($auth)); my $qtpasswdpath = $ENV{"QTSSADMINSERVER_QTSSQTPASSWD"}; if ($broadcastUsersArray[1] eq 'user') { $oldBroadcastUser = $broadcastUsersArray[2]; } # change the password in the passwords file # work on a copy if it's the current admin user if ($query->{'new_user'} ne $oldBroadcastUser) { if ($oldBroadcastUser ne $currentAdminUsername) { &passwordutils::DeleteUser($qtpasswdpath, $usersFilename, $groupsFilename, $oldBroadcastUser); } if (($query-{'allowUnrestrictedBroadcast'} ne '1') && ($query->{'new_user'} ne '')) { &passwordutils::AddOrEditBroadcastUser($qtpasswdpath, $usersFilename, $query->{'new_user'}, $query->{'new_password1'}); } } if ($query->{'allowUnrestrictedBroadcast'} eq '1') { $broadcastRestrictionString = "require any-user"; } elsif (($query->{'new_user'} ne '') && ($query->{'new_password1'} ne '')) { $broadcastRestrictionString = "require user " . $query->{'new_user'}; } my $viewingRestrictionString = join(' ', @$viewingUsersArrayRef); #&passwordutils::WriteRestrictionsToFile($filename, $broadcastRestrictionString, $viewingRestrictionString); # RemoveRestrictionsFile is for QTSS to sync with the server admin. Use WriteRestrictionsToFile above on Darwin Web Admins &passwordutils::RemoveRestrictionsFile($filename); $confirmMessage = $messages{'ChMP3PassSavedText'}; $filename = 'general_settings.html'; } sub ChangeMP3Password { my $messHash = adminprotolib::GetMessageHash(); my %messages = %$messHash; my $MP3BroadcastPasswordPath = "/admin/server/qtssSvrModuleObjects/QTSSMP3StreamingModule/qtssModPrefs/mp3_broadcast_password"; my $qtssPasswdName = $ENV{"QTSSADMINSERVER_QTSSQTPASSWD"}; my $qtssAdmin = $ENV{"QTSSADMINSERVER_QTSSADMIN"}; my $data = ''; $nextFilename = 'change_mp3_password.html'; if ($query->{'new_password1'} ne $query->{'new_password2'}) { $dialogHeader = $messages{'ChMP3PassNoMatchHeader'}; $dialogText = $messages{'ChMP3PassNoMatchText'}; return; } $status = &adminprotolib::SetAttribute($data, $messHash, $authheader, $qtssip, $qtssport, $MP3BroadcastPasswordPath, $query->{'new_password1'}); $confirmMessage = $messages{'ChMP3PassSavedText'}; $filename = $query->{'replaceFilename'}; if ($filename eq '') { $filename = 'general_settings.html'; } } # AssistSetPassword # returns 0 => failure # 1 => success sub AssistSetPassword { my $messHash = adminprotolib::GetMessageHash(); my %messages = %$messHash; my $usersFileAttributePath = "/server/qtssSvrModuleObjects/QTSSAccessModule/qtssModPrefs/modAccess_usersfilepath"; my $groupsFileAttributePath = "/server/qtssSvrModuleObjects/QTSSAccessModule/qtssModPrefs/modAccess_groupsfilepath"; my $usersFilePath = ''; my $groupsFilePath = ''; my $qtssPasswdName = $ENV{"QTSSADMINSERVER_QTSSQTPASSWD"}; my $qtssAdmin = $ENV{"QTSSADMINSERVER_QTSSADMIN"}; my $data = ''; my $line = ''; my $newUsername = $query->{'new_user'}; my $newPassword = $query->{'new_password1'}; my ($oldUsername, $authpass) = split(/:/, b64decode($auth)); $nextFilename = 'setup_assistant.html'; # if username or password is blank if (($query->{'new_user'} eq '') or ($query->{'new_password1'} eq '')) { $dialogHeader = $messages{'SetupAssistNoUsernameHeader'}; $dialogText = $messages{'SetupAssistNoUsername'}; return 0; } # if username has more than 255 characters if (length($query->{'new_user'}) > 255) { $dialogHeader = $messages{'ChPassUsernameNotLongerThan255Header'}; $dialogText = $messages{'ChPassUsernameNotLongerThan255Text'}; return 0; } # if username has a colon if ($query->{'new_user'} =~ /:/) { $dialogHeader = $messages{'ChPassUsernameCannotHaveColonHeader'}; $dialogText = $messages{'ChPassUsernameCannotHaveColonText'}; return 0; } # if username or password has a single quote or a double quote if ( ($query->{'new_user'} =~ /['"]/) || ($query->{'new_password1'} =~ /['"]/) ) { $dialogHeader = $messages{'ChPassCannotHaveQuotesHeader'}; $dialogText = $messages{'ChPassCannotHaveQuotesText'}; return 0; } # if password has more than 80 characters if (length($query->{'new_password1'}) > 80) { $dialogHeader = $messages{'ChPassNotLongerThan80Header'}; $dialogText = $messages{'ChPassNotLongerThan80Text'}; return 0; } # if new password #1 and new password #2 don't match if ($query->{'new_password1'} ne $query->{'new_password2'}) { $dialogHeader = $messages{'ChPassNoMatchHeader'}; $dialogText = $messages{'ChPassNoMatchText'}; return 0; } my $status = 200; if (($^O eq "darwin") and (-e "index.html") and (MacQTGroupsContainsAdminGroup() == 0)) { my $line = ''; $groupsFileText = ''; if (-e '/Library/QuickTimeStreaming/Config/qtgroups') { open(GROUPSFILE, '/Library/QuickTimeStreaming/Config/qtgroups') or die("Can't open groups file!"); while ($line = ) { $groupsFileText .= $line; } close(GROUPSFILE); } $groupsFileText .= "admin: $newUsername\n"; $groupsFilePath = '/Library/QuickTimeStreaming/Config/qtgroups'; my $extraargs = ''; my $qtpasswdpath = $ENV{'QTSSADMINSERVER_QTSSQTPASSWD'}; if (!(-e '/Library/QuickTimeStreaming/Config/qtusers')) { $extraargs = ' -c'; } if(system("$qtpasswdpath$extraargs -p \'$newPassword\' \'$newUsername\'") != 0) { $dialogHeader = $messages{'ChPassErrorHeader'}; $dialogText = $messages{'ChPassErrorText'}; return 0; } else { $status = 200 } } else { $status = &adminprotolib::EchoData($groupsFilePath, $messHash, $authheader, $qtssip, $qtssport, "/modules/admin$groupsFileAttributePath", "/modules/admin$groupsFileAttributePath"); if ($status == 401) { $auth = encodeBase64('aGFja21l:aGFja21l'); $authheader = "Authorization: Basic $auth\r\n"; $oldUsername = 'aGFja21l'; $status = &adminprotolib::EchoData($groupsFilePath, $messHash, $authheader, $qtssip, $qtssport, "/modules/admin$groupsFileAttributePath", "/modules/admin$groupsFileAttributePath"); } if ($status != 200) { $dialogHeader = $messages{'ChPassErrorHeader'}; $dialogText = $messages{'ChPassErrorText'}." ($status - $data)"; return 0; } $status = &adminprotolib::EchoData($usersFilePath, $messHash, $authheader, $qtssip, $qtssport, "/modules/admin$usersFileAttributePath", "/modules/admin$usersFileAttributePath"); if ($status != 200) { $dialogHeader = $messages{'ChPassErrorHeader'}; $dialogText = $messages{'ChPassErrorText'}." ($status - $data)"; return 0; } open(FILEHDL, "$groupsFilePath") or die "Can't open groups file '$groupsFilePath'!"; while ($line = ) { $groupsFileText .= $line; } close(FILEHDL); my $quotedOldUsername = quotemeta($oldUsername); $groupsFileText =~ s/([ \t:]+)$quotedOldUsername([\r\n\s]+)/$1$newUsername$2/; $status = &adminprotolib::SetPassword($data, $messageHash, $authheader, $qtssip, $qtssport, $usersFileAttributePath, $query->{'new_password1'}, $qtssPasswdName, $newUsername); if ($status != 200) { $dialogHeader = $messages{'ChPassErrorHeader'}; $dialogText = $messages{'ChPassErrorText'}." ($status - $data)"; return 0; } } open(FILEHDL, ">$groupsFilePath") or die "Can't open groups file '$groupsFilePath'!"; print FILEHDL $groupsFileText; close(FILEHDL); FixFileGroup($groupsFileText); # set the cookie and the auth header before calling DeleteUsername as the server expects the new username:password now my $newcookieval = encodeBase64($newUsername.':'.$query->{'new_password1'}); $cookie = 'qtsspassword='.$newcookieval.'; path=/'; $auth = $newcookieval; $authheader = "Authorization: Basic $auth\r\n"; if ($oldUsername ne $newUsername) { &adminprotolib::DeleteUsername($data, $messageHash, $authheader, $qtssip, $qtssport, $usersFileAttributePath, $qtssPasswdName, $oldUsername); } $dialogHeader = $messages{'ChPassSavedHeader'}; $dialogText = $messages{'ChPassSavedText'}; $filename = 'setup_assistant2.html'; return 1; } sub StartPlaylist { my $messHash = adminprotolib::GetMessageHash(); my %messages = %$messHash; my $curplaylist = $query->{'curplaylist'}; my $isRunning = &playlistlib::GetPlayListState($curplaylist); my $filedelim = &playlistlib::GetFileDelimChar(); my $plroot = &playlistlib::GetPLRootDir(); my $filedelim = &playlistlib::GetFileDelimChar(); my $targ = ''; my $targline = ''; my $plfiletext = ''; my $success = 0; my $targ = "$plroot$curplaylist$filedelim$curplaylist"; my $isRunning = &playlistlib::GetPlayListState($curplaylist); # open the playlist and re-save it so that the MP3 broadcast password is updated if necessary my $playlistdataref = &playlistlib::ParsePlayListEntry($curplaylist, $messHash); my $movieDir = ''; my $mp3BroadcastPassword = ''; my $status = adminprotolib::EchoData($movieDir, $messHash, $authheader, $qtssip, $qtssport, "/modules/admin/server/qtssSvrPreferences/movie_folder", "/modules/admin/server/qtssSvrPreferences/movie_folder"); $status = adminprotolib::EchoData($mp3BroadcastPassword, $messHash, $authheader, $qtssip, $qtssport, "/modules/admin/server/qtssSvrModuleObjects/QTSSMP3StreamingModule/qtssModPrefs/mp3_broadcast_password", "/modules/admin/server/qtssSvrModuleObjects/QTSSMP3StreamingModule/qtssModPrefs/mp3_broadcast_password"); if (&playlistlib::CreatePlayListEntry($curplaylist, $playlistdataref, $movieDir, $mp3BroadcastPassword) == 0) { $confirmMessage = ''; $filename = 'confirm.html'; $dialogHeader = $messages{'PLErrorHeader'}; $dialogText = $messages{'PLErrorHeader'}; $nextFilename = 'playlists.html'; return; } # playlist is re-saved if ("$isRunning" ne 1) { open(PLFILE, "$targ.config"); while ($targline = ) { $plfiletext .= $targline; } close(PLFILE); if ($plfiletext =~ /broadcast_genre /) { $isMP3 = 1; } else { $isMP3 = 0; } $success = &playlistlib::StartPlayList($curplaylist, $isMP3); if ($success != 1) { $filename = 'confirm.html'; $nextFilename = 'playlists.html'; $dialogHeader = $messages{'PLErrorHeader'}; $dialogText = $messages{'PLErrorText'}; return; } else { # successfully started the playlist! my $startfile = "$plroot$curplaylist$filedelim" . '.started'; # create a file in the playlist directory called .started # which we shall delete when we stop the playlist later open(STARTFILE, ">$startfile"); close(STARTFILE); FixFileGroup($startfile); chmod(0644, $startfile); } } # $confirmMessage = $messages{'PLChangedText'}; } sub StopPlaylist { my $messHash = adminprotolib::GetMessageHash(); my %messages = %$messHash; my $plroot = &playlistlib::GetPLRootDir(); my $filedelim = &playlistlib::GetFileDelimChar(); my $curplaylist = $query->{'curplaylist'}; my $isRunning = &playlistlib::GetPlayListState($curplaylist); my $filedelim = &playlistlib::GetFileDelimChar(); my $targ = ''; my $targline = ''; my $plfiletext = ''; my $targ = "$plroot$curplaylist$filedelim$curplaylist"; my $isRunning = &playlistlib::GetPlayListState($curplaylist); if ("$isRunning" ne $startstop{$i}) { # delete the file created when we started the playlist # even if we don't succeed in stopping the playlist # (which would only happen if we were reporting the wrong status # and the playlist was already stopped) my $startfile = "$plroot$curplaylist$filedelim" . '.started'; if ( -e $startfile) { unlink($startfile); } if (&playlistlib::StopPlayList($curplaylist) != 1) { $dialogHeader = $messages{'PLErrorHeader'}; $dialogText = $messages{'PLErrorText'}; return; } } # $confirmMessage = $messages{'PLChangedText'}; } sub ShowPlaylistLog { my $curplaylist = $query->{'curplaylist'}; $playlistErrorLogText = &playlistlib::EmitPlayListErrLogFile($curplaylist); } sub PLOpenDir { my $messHash = adminprotolib::GetMessageHash(); my %messages = %$messHash; my $genreArrayRef = adminprotolib::GetGenreArray(); $curplaylist = $query->{'curplaylist'}; $movieDir = $query->{'submitcurrentdir'}; } sub GetPlaylist { my $messHash = adminprotolib::GetMessageHash(); my %messages = %$messHash; my $genreArrayRef = adminprotolib::GetGenreArray(); $curplaylist = $query->{'curplaylist'}; my $playlistdataref = &playlistlib::ParsePlayListEntry($curplaylist, $messHash); my @playlistdata = @$playlistdataref; my $status = adminprotolib::EchoData($movieDir, $messHash, $authheader, $qtssip, $qtssport, "/modules/admin/server/qtssSvrPreferences/movie_folder", "/modules/admin/server/qtssSvrPreferences/movie_folder"); $currentDir = $movieDir; $plfilename = $playlistdata[0]; $plmode = $playlistdata[1]; $pllogging = $playlistdata[2]; $plfilesref = $playlistdata[3]; @plfiles = @$plfilesref; $plrep = $playlistdata[4]; $plgenre = $playlistdata[5]; $plbroadcastip = $playlistdata[6]; $plbroadcastusername = $playlistdata[7]; $plbroadcastpassword = $playlistdata[8]; $pltitle = $playlistdata[9]; if ($plgenre eq '') { $isMP3 = 0; $doctitle = $messages{'PLMoviePlaylistDetails'}; $extraFieldLabel = ''; $extraFieldHTML = ''; $playlistUsernameHTML = ' '.$messages{'Username'}.''; } else { $isMP3 = 1; $doctitle = $messages{'PLMP3PlaylistDetails'}; $extraFieldLabel = $messages{'PLGenre'}; $extraFieldHTML = ''; $playlistUsernameHTML = ''; } if ($plbroadcastip eq '127.0.0.1') { $plexternal = '0'; $plbroadcastusername = ''; $plbroadcastpassword = ''; } else { $plexternal = '1'; } } sub CreatePlaylist { my $messHash = adminprotolib::GetMessageHash(); my %messages = %$messHash; my $plroot = &playlistlib::GetPLRootDir(); my $fileDelimChar = &playlistlib::GetFileDelimChar(); my $movieDir = ''; my $mp3BroadcastPassword = ''; my $status = adminprotolib::EchoData($movieDir, $messHash, $authheader, $qtssip, $qtssport, "/modules/admin/server/qtssSvrPreferences/movie_folder", "/modules/admin/server/qtssSvrPreferences/movie_folder"); my $status = adminprotolib::EchoData($mp3BroadcastPassword, $messHash, $authheader, $qtssip, $qtssport, "/modules/admin/server/qtssSvrModuleObjects/QTSSMP3StreamingModule/qtssModPrefs/mp3_broadcast_password", "/modules/admin/server/qtssSvrModuleObjects/QTSSMP3StreamingModule/qtssModPrefs/mp3_broadcast_password"); my @plcontents = (); my $item = ''; my $plname = $query->{'qtssCurPlaylistName'}; my $i = 2; if ($plname eq '') { # no playlist filename yet... means this is a new playlist # set it to the playlist title $plname = $query->{'qtssCurPlaylistTitle'}; # drop all non-alphanumeric characters $plname =~ s/[^a-zA-Z0-9]//go; if (($plname eq '') or (-e "$plroot$plname$fileDelimChar")) { while (-e "$plroot$plname$fileDelimChar$i") { $i++; } $plname = "$plname$i"; } } else { if (-e "$plroot$plname$fileDelimChar$plname.err") { unlink "$plroot$plname$fileDelimChar$plname.err"; } } $i = 0; $nextFilename = 'playlists.html'; $confirmMessage = $messages{'PLCreatedText'}; my $qtssCurPlaylistURL = $plname.'.sdp'; if ($query->{'qtssCurPlaylistURL'} ne '') { $qtssCurPlaylistURL = $query->{'qtssCurPlaylistURL'}; } my $qtssCurPlaylistMode = $query->{'qtssCurPlaylistMode'}; my $playlistFiles = $query->{'submitplaylistfiles'}; $playlistFiles =~ s/%(..)/pack("c",hex($1))/ge; @plcontents = split(/\t/, $playlistFiles); my @submitplaylistweights = split(/\t/, $query->{'submitplaylistweights'}); foreach $item (@plcontents) { $item = "$item:$submitplaylistweights[$i++]"; } my $qtssCurPlaylistRep = '1'; if ($query->{'qtssCurPlaylistRep'} ne '') { $qtssCurPlaylistRep = $query->{'qtssCurPlaylistRep'}; } my $destipaddr = $query->{'plbroadcastip'}; my $broadcastusername = $query->{'plbroadcastusername'}; my $broadcastpassword = $query->{'plbroadcastpassword'}; if (($query->{'plexternal'} ne '1') or ($destipaddr eq '')) { $destipaddr = '127.0.0.1'; $broadcastusername = ''; $broadcastpassword = ''; } my @plsettings = ($qtssCurPlaylistURL,$qtssCurPlaylistMode,$query->{'pllogging'},\@plcontents,$qtssCurPlaylistRep,$query->{'PLGenre'},$destipaddr,$broadcastusername,$broadcastpassword,$query->{'qtssCurPlaylistTitle'}); if (&playlistlib::CreatePlayListEntry($plname, \@plsettings, $movieDir, $mp3BroadcastPassword) == 0) { $confirmMessage = ''; $filename = 'confirm.html'; $dialogHeader = $messages{'PLCreateErrorHeader'}; $dialogText = $messages{'PLCreateErrorText'}; $nextFilename = 'playlists.html'; } } # NewPlaylist expects the var isMP3 to be set to 0 or 1 sub NewPlaylist { my $messHash = adminprotolib::GetMessageHash(); my %messages = %$messHash; my $genreArrayRef = &adminprotolib::GetGenreArray(); my @genreArray = @$genreArrayRef; my $status = adminprotolib::EchoData($movieDir, $messHash, $authheader, $qtssip, $qtssport, "/modules/admin/server/qtssSvrPreferences/movie_folder", "/modules/admin/server/qtssSvrPreferences/movie_folder"); $currentDir = useDefaultIfBlank($query->{'currentdir'}, $movieDir); $plrep = 1; @plfiles = (); $plrep = '1'; $curplaylist = ''; $pltitle = ''; $plfilename = ''; $plmode = ''; $pllogging = ''; $plbroadcastip = '127.0.0.1'; $plbroadcastusername = ''; $plbroadcastpassword = ''; if ($isMP3 == 1) { $doctitle = $messages{'PLMP3PlaylistDetails'}; $extraFieldLabel = $messages{'PLGenre'}; $extraFieldHTML = ''; $playlistUsernameHTML = ''; $pltitle = $messages{'PLDefaultPlaylistName'}; $plfilename = $messages{'PLDefaultMP3PlaylistMountPoint'}; } else { $doctitle = $messages{'PLMoviePlaylistDetails'}; $extraFieldLabel = ''; $extraFieldHTML = ''; $playlistUsernameHTML = ' '.$messages{'Username'}.''; $pltitle = $messages{'PLDefaultPlaylistName'}; $plfilename = $messages{'PLDefaultMoviePlaylistSDP'}; } } sub RefreshPlaylistDir() { my $messHash = adminprotolib::GetMessageHash(); my %messages = %$messHash; my $genreArrayRef = &adminprotolib::GetGenreArray(); my @genreArray = @$genreArrayRef; my $i = 0; my $playlistFiles = $query->{'submitplaylistfiles'}; $playlistFiles =~ s/%(..)/pack("c",hex($1))/ge; my @plcontents = split(/\t/, $playlistFiles); my @submitplaylistweights = split(/\t/, $query->{'submitplaylistweights'}); @plfiles = (); my $status = adminprotolib::EchoData($movieDir, $messHash, $authheader, $qtssip, $qtssport, "/modules/admin/server/qtssSvrPreferences/movie_folder", "/modules/admin/server/qtssSvrPreferences/movie_folder"); foreach $item (@plcontents) { push(@plfiles, "$item:$submitplaylistweights[$i++]"); } $currentDir = $query->{'submitcurrentdir'}; $currentDir =~ s/%(..)/pack("c",hex($1))/ge; $query->{'submitcurrentdir'} = ''; $isMP3 = $query->{'isMP3'}; $plrep = $query->{'qtssCurPlaylistRep'}; $curplaylist = $query->{'qtssCurPlaylistName'}; $pltitle = $query->{'qtssCurPlaylistTitle'}; $plfilename = $query->{'qtssCurPlaylistURL'}; $plmode = $query->{'qtssCurPlaylistMode'}; $plrep = $query->{'qtssCurPlaylistRep'}; $plgenre = $query->{'PLGenre'}; $pllogging = $query->{'pllogging'}; $plbroadcastip = $query->{'plbroadcastip'}; $plbroadcastusername = $query->{'plbroadcastusername'}; $plbroadcastpassword = $query->{'plbroadcastpassword'}; if ($isMP3 == 0) { $doctitle = $messages{'PLMoviePlaylistDetails'}; $extraFieldLabel = ''; $extraFieldHTML = ''; $playlistUsernameHTML = ' '.$messages{'Username'}.''; } else { $doctitle = $messages{'PLMP3PlaylistDetails'}; $extraFieldLabel = $messages{'PLGenre'}; $extraFieldHTML = ''; $playlistUsernameHTML = ''; } if (($plbroadcastip eq '127.0.0.1') or ($plbroadcastip eq '')) { $plexternal = '0'; $plbroadcastusername = ''; $plbroadcastpassword = ''; } else { $plexternal = '1'; } } sub DeletePlaylist { my $messHash = adminprotolib::GetMessageHash(); my %messages = %$messHash; if (&playlistlib::RemovePlaylistDir($query->{'curplaylist'}) == 1) { $confirmText = $messages{'PLDeleteText'}; } else { $filename = 'confirm.html'; $nextFilename = 'playlists.html'; $dialogHeader = $messages{'PLDeleteErrorHeader'}; $dialogText = $messages{'PLDeleteErrorText'}; } } sub ResetErrorLog { my $chdelim = &playlistlib::GetFileDelimChar(); my $messHash = adminprotolib::GetMessageHash(); my %messages = %$messHash; my $responseText = ''; my $status = adminprotolib::GetData($responseText, $messHash, $authheader, $qtssip, $qtssport, '/modules/admin/server/qtssSvrPreferences/error_logfile_dir'); $_ = $responseText; $confirmMessage = 'redirect'; if (!(/error_logfile_dir="([^"]+)"/)) { die('Error getting logfile dir.'); } my $dirname = $1; $status = adminprotolib::GetData($responseText, $messHash, $authheader, $qtssip, $qtssport, '/modules/admin/server/qtssSvrPreferences/error_logfile_name'); $_ = $responseText; if (!(/error_logfile_name="([^"]+)"/)) { die('Error getting filename.'); } $logname = $1; $logfilename = $dirname . $chdelim . $logname . '.log'; $logfilename =~ s/\/{2,}/\//g; # remove duplicate slashes if (-e $logfilename) { $rolldatestr = sprintf("%02d%02d%02d", sub {($_[5] % 100, $_[4]+1, $_[3])}->(localtime)); $rollfilenumber = 0; $rollfilename = "$dirname$chdelim" . $logname . ".$rolldatestr" . '000.log'; while (-e $rollfilename) { $rollfilenumber++; $rollfilename = "$dirname$chdelim" . $logname . ".$rolldatestr" . sprintf("%03d", $rollfilenumber) . '.log'; } $rollfilename =~ s/\/{2,}/\//g; # remove duplicate slashes `/bin/mv "$logfilename" "$rollfilename"`; #unlink($dirname); } $confirmMessage = $messages{'ErrorLogResetConf'}; } sub SaveBroadcasterSettings { my $restartBroadcaster = 0; my $changedNetworkSetting = 0; my %messages = %$messageHash; if (!$broadcasterConn) { RestartBroadcaster(); if (!$broadcasterConn) { $filename = 'start_broadcaster.html'; return false; } } if (($broadcasterConn->state != 0) && ($theAction eq 'SaveBroadcasterSettings')) { $restartBroadcaster = 1; $broadcasterConn->stopBroadcast; } if ($query->{'qtbCurrentAudioPreset'} ne $query->{'qtbCurrentAudioPreset_shadow'}) { $changedNetworkSetting = 1; &broadcasterlib::SetCurrentPresetForType($broadcasterConn, 0, $query->{'qtbCurrentAudioPreset'}); } if ($query->{'qtbCurrentVideoPreset'} ne $query->{'qtbCurrentVideoPreset_shadow'}) { $changedNetworkSetting = 1; &broadcasterlib::SetCurrentPresetForType($broadcasterConn, 1, $query->{'qtbCurrentVideoPreset'}); } if ($query->{'qtbAudioStreamEnabled'} ne $query->{'qtbAudioStreamEnabled_shadow'}) { &broadcasterlib::SetStreamEnabledForType($broadcasterConn, 0, $query->{'qtbAudioStreamEnabled'}); } if ($query->{'qtbVideoStreamEnabled'} ne $query->{'qtbVideoStreamEnabled_shadow'}) { &broadcasterlib::SetStreamEnabledForType($broadcasterConn, 1, $query->{'qtbVideoStreamEnabled'}); } if ($query->{'qtbRecordingPath'} ne $query->{'qtbRecordingPath_shadow'}) { &broadcasterlib::SetRecordingPath($broadcasterConn, $query->{'qtbRecordingPath'}); } if ($query->{'qtbNetworkPresetSDPFilename'} ne $query->{'qtbNetworkPresetSDPFilename_shadow'}) { $changedNetworkSetting = 1; &broadcasterlib::SetNetworkFilepath($query->{'qtbNetworkPresetSDPFilename'}); } if ($query->{'qtbBufferDelay'} ne $query->{'qtbBufferDelay_shadow'}) { $changedNetworkSetting = 1; &broadcasterlib::SetBufferDelay($query->{'qtbBufferDelay'}); } if ($changedNetworkSetting == 1) { &broadcasterlib::RereadSettingsFile($broadcasterConn); } if (($restartBroadcaster) && ($theAction eq 'SaveBroadcasterSettings')) { StartStopBroadcast(); } if ($confirmMessage ne $messages{'QTBErrBroadcastSettings'}) { $confirmMessage = $messages{'QTBConfSaved'}; } } sub StartStopBroadcast { if ($theAction eq 'StartStopBroadcast') { SaveBroadcasterSettings(); } my %messages = %$messageHash; my $messageName = ''; if ($broadcasterConn) { $messageName = &broadcasterlib::StartStopBroadcast($broadcasterConn); } $confirmMessage = $messages{$messageName}; if ($messageName eq '') { # couldn't start broadcast $confirmMessage = $messages{'QTBErrBroadcastSettings'}; } if ($messageName eq 'QTBConfStarted') { my $value = '/modules/admin/server/qtssSvrDefaultDNSName'; my $data = ''; my $status = adminprotolib::EchoData($data, $messHash, $authheader, $qtssip, $qtssport, $value, $value); &broadcasterlib::WriteRefMovie($data); my $cycles = 0; my $continue = 1; my $state; while ($continue == 1) { sleep(1); $state = &broadcasterlib::GetBroadcasterStateID($broadcasterConn); $cycles = $cycles + 1; if (($cycles > 7) || ($state == 3)) { $continue = 0; } } if ($state != 3) { $confirmMessage = $messages{'QTBErrBroadcastSettings'}; } } } sub RestartBroadcaster { eval("require 'broadcaster_lib.pl';"); &broadcasterlib::KillServer(1); sleep(1); ConnectToBroadcaster(1); } # this routine performs an action, if there is any sub PerformAction { my $messHash = adminprotolib::GetMessageHash(); my %messages = %$messHash; if ($theAction eq 'refreshmessages') { # refresh the message hashes from the correct files. &streamingadminserver::LoadMessageHashes(); } elsif ($theAction eq 'login') { $cookie = 'qtsspassword='.encodeBase64($query->{'qtssusername'}.':'.$query->{'qtsspassword'}).'; path=/'; return true; } elsif ($theAction eq 'logout') { $cookie = 'qtsspassword=; path=/'; return true; } elsif ($theAction eq 'StartStopServer') { StartStopServer(); } elsif ($theAction eq 'restartadminserver') { restart_streamingadminserver(); return true; } elsif ($theAction eq 'setrefresh') { if (getCookie('pageRefreshInterval') ne $query->{'pageRefreshInterval'}) { $cookie = 'pageRefreshInterval='.$query->{'pageRefreshInterval'}.'; path=/'; } else { $cookie = 'displayCount='.$query->{'displayCount'}.'; path=/'; } return true; } elsif ($theAction eq 'setconnusersort') { $cookie = 'connUserSort='.$query->{'connUserSort'}; } elsif ($theAction eq 'setrelaystatsort') { $cookie = 'relayStatSort='.$query->{'relayStatSort'}; } elsif ($theAction eq 'SaveGeneralSettings') { SaveGeneralSettings(); } elsif ($theAction eq 'ChangePassword') { ChangePassword(); } elsif ($theAction eq 'ConfirmPassChanged') { $confirmMessage = $messages{'ChPassSavedText'}; } elsif ($theAction eq 'ChangeMP3Password') { ChangeMP3Password(); } elsif ($theAction eq 'ChangeBroadcastPassword') { ChangeBroadcastPassword(); } elsif ($theAction eq 'SaveLogSettings') { SaveLogSettings(); } elsif ($theAction eq 'SavePortSettings') { SavePortSettings(); } elsif ($theAction eq 'StartPlaylist') { StartPlaylist(); } elsif ($theAction eq 'StopPlaylist') { StopPlaylist(); } elsif ($theAction eq 'ShowPlaylistLog') { ShowPlaylistLog(); } elsif ($theAction eq 'GetPlaylist') { GetPlaylist(); } elsif ($theAction eq 'CreatePlaylist') { CreatePlaylist(); } elsif ($theAction eq 'NewMP3Playlist') { $isMP3 = 1; NewPlaylist(); } elsif ($theAction eq 'NewMoviePlaylist') { $isMP3 = 0; NewPlaylist(); } elsif ($theAction eq 'RefreshPlaylistDir') { RefreshPlaylistDir(); } elsif ($theAction eq 'DeletePlaylist') { DeletePlaylist(); } elsif ($theAction eq 'getValsForRelay') { getValsForRelay(); } elsif ($theAction eq 'getNewRelay') { getNewRelay(); } elsif ($theAction eq 'getRelayDestData') { getRelayDestData(); } elsif ($theAction eq 'SetRelayDestData') { SetRelayDestData(); } elsif ($theAction eq 'AddRelayDestination') { AddRelayDestination(); } elsif ($theAction eq 'DeleteRelayDest') { DeleteRelayDest(); } elsif ($theAction eq 'SaveRelay') { SaveRelay(); } elsif ($theAction eq 'DeleteRelay') { DeleteRelay(); $confirmMessage = $messages{'RelayDeleteText'}; } elsif ($theAction eq 'RunAssistant') { RunAssistant(); if (-e "index.html") { unlink("index.html"); } } elsif ($theAction eq 'AssistSetPassword') { my $setupAssistantPasswordSuccess = AssistSetPassword(); if (($setupAssistantPasswordSuccess == 1) && (-e "index.html")) { unlink("index.html"); } } elsif ($theAction eq 'ResetErrorLog') { ResetErrorLog(); } elsif ($theAction eq 'SaveBroadcasterSettings') { SaveBroadcasterSettings(); } elsif ($theAction eq 'StartStopBroadcast') { StartStopBroadcast(); } elsif ($theAction eq 'StartBroadcaster') { eval("require 'broadcaster_lib.pl';"); ConnectToBroadcaster(1); sleep(3); } elsif ($theAction eq 'RestartBroadcaster') { RestartBroadcaster(); } elsif ($theAction eq 'QuitBroadcaster') { eval("require 'broadcaster_lib.pl';"); ConnectToBroadcaster(0); if (!(!$broadcasterConn || !$$broadcasterConn)) { &broadcasterlib::QuitBroadcaster($broadcasterConn); } my %messages = %$messageHash; $confirmMessage = $messages{'QTBConfQuit'}; } elsif ($theAction eq '') { return true; } else { die("Action not found!"); } } # post method environment variable $cl = $ENV{"CONTENT_LENGTH"}; if ($ENV{"REQUEST_METHOD"} eq "POST") { # put the data into a variable read(STDIN, $qs, $cl); $query = &adminprotolib::ParseQueryString($qs); } elsif ($ENV{"REQUEST_METHOD"} eq "GET") { $qs = $ENV{"QUERY_STRING"}; $query = &adminprotolib::ParseQueryString($qs); } # get the filename $filename = $query->{'filename'}; if (($filename =~ /[^A-Za-z0-9_\-\.\/]/) or ($filename =~ /\.{2,}/) or ($filename =~ /\/{2,}/)) { die "Can't access HTML file!"; } $auth = $query->{'qtsspassword'}; $username = $query->{'qtssusername'}; $cookie = $query->{'cookie'}; $confirmMessage = ''; $chdelim = &playlistlib::GetFileDelimChar(); $serverRoot = $ENV{"SERVER_ROOT"}; # fix for 3148849 # if the filename starts with /, remove the slash $filename =~ s/^\///; # fix for 3064725 # if the setup assistant is being called and the index file no longer exists, # clear $filename so we get the frameset instead if (($filename =~ m/setup_assistant2/) && (!(-e "$serverRoot/index.html"))) { $filename = ''; } # new auth code if ($auth eq '') { #if ($cookies{'qtsspassword'}) { # $auth = $cookies{'qtsspassword'}->value; #} # can't use CGI library; parsing by hand if (getCookie('qtsspassword')) { $auth = getCookie('qtsspassword'); } } else { $auth = encodeBase64("$username:$auth"); } $authheader = "Authorization: Basic $auth\r\n"; $theAction = $query->{'action'}; $wasAuth = 1; # fake a found tag to force authentication before performing an action if (($theAction ne '') && !($nonAuthenticatedActions =~ m/\|$theAction\|/o)) { foundTag(' name="qtssSvrDefaultDNSName"', '', '/'); if ($wasAuth <= 0) { undef($query); undef($qs); return 0; } } # run the action if there is one PerformAction(); # hack for QT Broadcaster library on Mac OS X Only if ($filename eq 'broadcaster_settings.html') { if (!(-e '/Applications/QuickTime Broadcaster.app')) { my %messages = %$messageHash; $confirmMessage = $messages{'QTBErrNotInstalledText'}; $filename = 'welcome.html'; } else { my $result = ConnectToBroadcaster(0); if ($result == 0) { # couldn't connect to broadcaster $filename = 'start_broadcaster.html'; } elsif ($result == (-1)) { $filename = 'restart_broadcaster.html'; } } } if ($confirmMessage ne '') { # if we're confirming a save, then do a redirect from the post operation. if ($confirmMessage eq 'redirect') { $confirmMessage = ''; } else { $confirmMessage =~ s/\s/%20/g; $confirmMessage =~ s/&/%26/g; } &cgilib::PrintRedirectHeader($ENV{"SERVER_SOFTWARE"}, "/parse_xml.cgi?filename=$filename&confirmMessage=$confirmMessage"); return 0; } else { $confirmMessage = $query->{'confirmMessage'}; chdir($ENV{"SERVER_ROOT"}); # default here if (($filename eq '') or (($filename eq 'login.html') and ($query->{'action'} eq 'login'))) { $filename = "frameset.html"; } if ($templatefile eq '') { $templatefile = "template.html"; } #prevent source code revelation if (!($filename =~ m/\.html$/)) { die "Can't access HTML file '$filename'!"; } #prevent windows ports from being opened #aux, con, prn, com*, lpt?, nul $foundFilename = 0; opendir(FILEDIR, $ENV{"SERVER_ROOT"}) or die "Can't access HTML file '$filename'!"; while (defined($subpath = readdir(FILEDIR))) { $foundFilename = 1 if $subpath eq $filename; } die "Can't access HTML file '$filename'!" if $foundFilename == 0; $text = ''; $templatetext = ''; if (!(-e "$filename")) { die "Can't access HTML file '$filename'!"; } open(HTMLFILE, $filename) or die "Can't open HTML file '$filename'!"; # read the entire file into while ($line = ) { $text .= $line; } # we're done with the file; now close it close(HTMLFILE); # if the template contains the tag, replace it with the body text from the file if ($templatetext =~ //gix) { $templatetext =~ s//$text/gix; $text = $templatetext; } # parse the tags in the file's text $text = parseTags($text); if ($wasAuth <= 0) { undef($query); undef($qs); return 0; } # used to be makeSecureRoot() if ($^O ne "MSWin32") { chroot($ENV{"SERVER_ROOT"}); die "Can't open HTML file '$filename!'" if (!(-e $ENV{"SERVER_ROOT"}.'/'.$filename)); } if (($^O eq "MSWin32") && &adminprotolib::CheckIfForbidden($ENV{"SERVER_ROOT"}, $filename)) { die "Can't open HTML file '$filename'!"; } open(HTMLFILE, $filename) or die "Can't open HTML file '$filename'!"; close(HTMLFILE); # give them a new cookie unless we have a better plan for them if ($cookie eq '') { $cookie = 'qtsspassword='.getCookie('qtsspassword').'; path=/'; } # CGI programs must print their own HTTP response headers &cgilib::PrintOKTextHeader($servername, $cookie); #print the replaced HTML print $text; } # done! undef($query); undef($qs); return 0;