ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/utils/player_dl.pl.in
(Generate patch)

Comparing deliantra/server/utils/player_dl.pl.in (file contents):
Revision 1.1.1.1 by root, Fri Feb 3 07:14:50 2006 UTC vs.
Revision 1.2 by root, Mon Mar 5 19:03:09 2007 UTC

1#!/usr/bin/perl -w 1#!/usr/bin/perl -w
2################## 2##################
3# Playerfile download utility. 3# Playerfile download utility.
4# Version 1.2 4# Version 1.2
5#### 5####
6# Note: This file requires the CGI.pm module to operate. 6# Note: This file requires the CGI.pm module to operate.
7# The player_dl.html file is a basic web page which 7# The player_dl.html file is a basic web page which
8# can be used for downloads. 8# can be used for downloads.
9# 9#
10# This CGI script allows players to download their players 10# This CGI script allows players to download their players
11# files through a web interface. It does password checking 11# files through a web interface. It does password checking
12# and has some extra options. 12# and has some extra options.
13# 13#
14# Note 2: The player files and directories need to be readable 14# Note 2: The player files and directories need to be readable
15# by whatever uid runs this program. In many cases, this may be 15# by whatever uid runs this program. In many cases, this may be
16# nobody or apache or whatever. This script does not differentiate 16# nobody or apache or whatever. This script does not differentiate
17# invalid password or lack of ability to read player files. If 17# invalid password or lack of ability to read player files. If
21# Note 3: on some systems, differnet password encryption schemes 21# Note 3: on some systems, differnet password encryption schemes
22# are used. Eg, on windows, no encryption is used at all, while 22# are used. Eg, on windows, no encryption is used at all, while
23# on others, if des_crypt is available, that is used instead. 23# on others, if des_crypt is available, that is used instead.
24# this script would need modification to cover those cases. 24# this script would need modification to cover those cases.
25# 25#
26#### 26####
27# Copyright (c) 2003 by Philip Stolarczyk 27# Copyright (c) 2003 by Philip Stolarczyk
28# This program is free software; you can redistribute it 28# This program is free software; you can redistribute it
29# and/or modify it under the terms of the GNU General Public 29# and/or modify it under the terms of the GNU General Public
30# License as published by the Free Software Foundation; 30# License as published by the Free Software Foundation;
31# either version 2 of the License, or (at your option) any 31# either version 2 of the License, or (at your option) any
32# later version. 32# later version.
33# This program is distributed in the hope that it will be 33# This program is distributed in the hope that it will be
34# useful, but WITHOUT ANY WARRANTY; without even the implied 34# useful, but WITHOUT ANY WARRANTY; without even the implied
35# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 35# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
36# PURPOSE. See the GNU General Public License for more 36# PURPOSE. See the GNU General Public License for more
37# details. 37# details.
38#### 38####
39# Config options: 39# Config options:
40# 40#
41# Where the tar program is located. 41# Where the tar program is located.
42$tar = '@TAR@'; 42$tar = '@TAR@';
43 43
44$prefix="@prefix@"; 44$prefix="@prefix@";
45# Where the crossfire directory is located. 45# Where the crossfire directory is located.
46$crossfire_home = "@pkgstatedir@/players"; 46$crossfire_home = "@pkgstatedir@/players";
47 47
48# Where to save temporary files 48# Where to save temporary files
49$temp_dir = '/tmp'; 49$temp_dir = '/tmp';
50 50
51# How often a player can have their file sent to them, in seconds. (ie. 3600 is once/hour), set to 0 to disable. 51# How often a player can have their file sent to them, in seconds. (ie. 3600 is once/hour), set to 0 to disable.
52$timelimit = 3600; 52$timelimit = 3600;
53 53
54# Where to save information on when which player files were downloaded, for the time limit function. 54# Where to save information on when which player files were downloaded, for the time limit function.
55$statefile = "$temp_dir/pldl.dat"; 55$statefile = "$temp_dir/pldl.dat";
56 56
57# Whether to delete the player's file after they download it. 57# Whether to delete the player's file after they download it.
58$delete_player = 0; 58$delete_player = 0;
59 59
60# 60#
61#### 61####
62# BUGS: 62# BUGS:
63# Systems that do NL to CRLF interpretation on CGI output 63# Systems that do NL to CRLF interpretation on CGI output
64# will corrupt the .tar file. This includes Microsoft 64# will corrupt the .tar file. This includes Microsoft
65# Windows systems. I haven't found any solution. 65# Windows systems. I haven't found any solution.
66################## 66##################
67# Code begins. 67# Code begins.
68 68
69use CGI; 69use CGI;
70use CGI::Carp 'fatalsToBrowser'; 70use CGI::Carp 'fatalsToBrowser';
71$CGI::POST_MAX=1024; # max 1K posts 71$CGI::POST_MAX=1024; # max 1K posts
72$CGI::DISABLE_UPLOADS = 1; # no uploads 72$CGI::DISABLE_UPLOADS = 1; # no uploads
73 73
74$q = new CGI; 74$q = new CGI;
75 75
76# Verify that player name contains no invalid characters. 76# Verify that player name contains no invalid characters.
77$playername = ''; 77$playername = '';
78$playername = $q->param('playername') if $q->param('playername'); 78$playername = $q->param('playername') if $q->param('playername');
79$playername =~ s/[^A-Za-z_\-]//g; # No invalid chars 79$playername =~ s/[^A-Za-z_\-]//g; # No invalid chars
80$playername =~ s/^(.{1,64}).*$/$1/; # Max 64 chars, (really it's 16 or 32 in the server) 80$playername =~ s/^(.{1,64}).*$/$1/; # Max 64 chars, (really it's 16 or 32 in the server)
81 81
82# Default to not validated, until the password is checked. 82# Default to not validated, until the password is checked.
83$valid = 0; 83$valid = 0;
84 84
85# No error to report yet. 85# No error to report yet.
86$errormsg = ''; 86$errormsg = '';
87 87
88# We want to the time we ran to be consistent, even if it takes a couple seconds. 88# We want to the time we ran to be consistent, even if it takes a couple seconds.
89$time = time(); 89$time = time();
90 90
91 91
92# Validate password 92# Validate password
93$password = $q->param('password'); 93$password = $q->param('password');
94if ($playername) { # Make sure that the user typed in a playername. 94if ($playername) { # Make sure that the user typed in a playername.
95 if ((open PLAYERFILE, "$crossfire_home/$playername/$playername.pl") # Make sure the player's file exists 95 if ((open PLAYERFILE, "$crossfire_home/$playername/$playername.pl") # Make sure the player's file exists
96 or (open PLAYERFILE, "$crossfire_home/$playername/$playername.pl.dead")) { # Or use the dead file, if no player is alive 96 or (open PLAYERFILE, "$crossfire_home/$playername/$playername.pl.dead")) { # Or use the dead file, if no player is alive
97 foreach (<PLAYERFILE>) { 97 foreach (<PLAYERFILE>) {
98 chomp; chomp; 98 chomp; chomp;
99 # Do actual checking of password. 99 # Do actual checking of password.
100 if ( /^password (.*)$/ ) { 100 if ( /^password (.*)$/ ) {
101 $cp = crypt($password,$1); 101 $cp = crypt($password,$1);
102 if ($cp eq $1) { 102 if ($cp eq $1) {
103 $valid = 1; 103 $valid = 1;
104 } 104 }
105 } 105 }
106 } 106 }
107 close PLAYERFILE; 107 close PLAYERFILE;
108 } 108 }
109} 109}
110if (!$valid) { $errormsg = 'Invalid username or password' }; 110if (!$valid) { $errormsg = 'Invalid username or password' };
111 111
112# If the player is validated, and we're limiting how often players can download their files, do so. 112# If the player is validated, and we're limiting how often players can download their files, do so.
113if ($valid and $timelimit and $statefile) { 113if ($valid and $timelimit and $statefile) {
114 open STATEFILE, "<$statefile"; 114 open STATEFILE, "<$statefile";
115 @contents = <STATEFILE>; 115 @contents = <STATEFILE>;
116 close STATEFILE; 116 close STATEFILE;
117 # Don't allow more than 1024 players to download their files per $timelimit seconds. 117 # Don't allow more than 1024 players to download their files per $timelimit seconds.
118 # This is to prevent STATEFILE from getting too large. 118 # This is to prevent STATEFILE from getting too large.
119 if ($#contents > 1024) { 119 if ($#contents > 1024) {
120 $valid = 0; 120 $valid = 0;
121 $errormsg = 'Too many players have tried to download their files recently. Please wait a bit before trying again.\n'; 121 $errormsg = 'Too many players have tried to download their files recently. Please wait a bit before trying again.\n';
122 } 122 }
123 123
124 # Check timestamp of last download for this player 124 # Check timestamp of last download for this player
125 foreach (@contents) { 125 foreach (@contents) {
126 chomp; chomp; 126 chomp; chomp;
127 if (/^DL $playername (.*)$/) { 127 if (/^DL $playername (.*)$/) {
128 # $1 is the last time the file was DLed. 128 # $1 is the last time the file was DLed.
129 if ($time > ($timelimit + $1)) { 129 if ($time > ($timelimit + $1)) {
130 $valid = 0; 130 $valid = 0;
131 $errormsg = 'You just downloaded your file. Wait a bit before trying again.'; 131 $errormsg = 'You just downloaded your file. Wait a bit before trying again.';
132 } 132 }
133 } 133 }
134 } 134 }
135} 135}
136 136
137if ($valid) { 137if ($valid) {
138 # Create and send file 138 # Create and send file
139 139
140 # Create a new archive 140 # Create a new archive
141 # Sending binary data. 141 # Sending binary data.
142 # Add content-disposition, in this way, the browser (at least mozilla) 142 # Add content-disposition, in this way, the browser (at least mozilla)
143 # will use it as the default filename, instead of the cgi script name. 143 # will use it as the default filename, instead of the cgi script name.
144 print $q->header(-type=>"application/x-compressed-tar", 144 print $q->header(-type=>"application/x-compressed-tar",
145 "-content-disposition"=>"inline; filename=\"$playername.tar\""); 145 "-content-disposition"=>"inline; filename=\"$playername.tar\"");
146 146
147 # Change to player directory, so that long pathname is not included in 147 # Change to player directory, so that long pathname is not included in
148 # sent file. 148 # sent file.
149 chdir("$crossfire_home"); 149 chdir("$crossfire_home");
150 # archive up the player 150 # archive up the player
151 system("$tar -cf - $playername"); 151 system("$tar -cf - $playername");
152 152
153 # 'Delete' player's files, if applicable. (technically rename them, to hide from server.) 153 # 'Delete' player's files, if applicable. (technically rename them, to hide from server.)
154 if ($valid and $delete_player) { 154 if ($valid and $delete_player) {
155 @files= glob("$crossfire_home/$playername/*"); 155 @files= glob("$crossfire_home/$playername/*");
156 # Rename all files except *.tar 156 # Rename all files except *.tar
157 foreach (@files) { 157 foreach (@files) {
158 next if ( /\.tar$/i ); 158 next if ( /\.tar$/i );
159 rename $_, "$_.downloaded"; 159 rename $_, "$_.downloaded";
160 } 160 }
161 } 161 }
162 162
163 # Set timestamp of last download for this player, if applicable. 163 # Set timestamp of last download for this player, if applicable.
164 # Also, remove outdated player download timestamps, if applicable. 164 # Also, remove outdated player download timestamps, if applicable.
165 if ($timelimit > 0 and $statefile) { 165 if ($timelimit > 0 and $statefile) {
166 if (open STATEFILE, "<$statefile") { 166 if (open STATEFILE, "<$statefile") {
167 @contents = <STATEFILE>; 167 @contents = <STATEFILE>;
168 close STATEFILE; 168 close STATEFILE;
169 } else { 169 } else {
170 @contents = (); 170 @contents = ();
171 } 171 }
172 172
173 if (open STATEFILE, ">$statefile") { 173 if (open STATEFILE, ">$statefile") {
174 foreach (@contents) { 174 foreach (@contents) {
175 chomp; chomp; 175 chomp; chomp;
176 if (/^DL (.*) (.*)$/) { 176 if (/^DL (.*) (.*)$/) {
177 # All lines starting with DL are download time records. 177 # All lines starting with DL are download time records.
178 my ($playerdownloaded, $timedownloaded) = ($1, $2); 178 my ($playerdownloaded, $timedownloaded) = ($1, $2);
179 179
180 # If this player just downloaded their file, don't copy them yet. We update their timestamp later. 180 # If this player just downloaded their file, don't copy them yet. We update their timestamp later.
181 next if ($valid and ($playerdownloaded eq $playername)); 181 next if ($valid and ($playerdownloaded eq $playername));
182 # If this record has expired, don't copy it. 182 # If this record has expired, don't copy it.
183 next if (($timedownloaded + $timelimit) < $time); 183 next if (($timedownloaded + $timelimit) < $time);
184 # Otherwise, copy the record to the new state file. 184 # Otherwise, copy the record to the new state file.
185 print "$_\n"; 185 print "$_\n";
186 } else { 186 } else {
187 # Allow other lines in this file. 187 # Allow other lines in this file.
188 print "$_\n"; 188 print "$_\n";
189 } 189 }
190 } 190 }
191 # If this player downloaded their file, save it. 191 # If this player downloaded their file, save it.
192 if ($valid) { 192 if ($valid) {
193 print STATEFILE "DL $playername $time\n"; 193 print STATEFILE "DL $playername $time\n";
194 } 194 }
195 close STATEFILE; 195 close STATEFILE;
196 } else { 196 } else {
197 die "Unable to save state to file $statefile.\n"; 197 die "Unable to save state to file $statefile.\n";
198 } 198 }
199 } 199 }
200} 200}
201 201
202# If no file was sent, send a form and any error messages. 202# If no file was sent, send a form and any error messages.
203if (!$valid) { 203if (!$valid) {
204 print $q->header('text/html'); 204 print $q->header('text/html');
205 205
206 # Print header 206 # Print header
207 print $q->start_html('Download your player file'); 207 print $q->start_html('Download your player file');
208 print "\n\n\n"; 208 print "\n\n\n";
209 209
210 # print any error message that may have occured. 210 # print any error message that may have occured.
211 if ($errormsg) { 211 if ($errormsg) {
212 print $q->h3("ERROR: ". $errormsg), $q->br(), $q->br(); 212 print $q->h3("ERROR: ". $errormsg), $q->br(), $q->br();
213 } 213 }
214 214
215 # Print warnings if $delete_player is enabled. 215 # Print warnings if $delete_player is enabled.
216 if ($delete_player) { 216 if ($delete_player) {
217 print <<'(END)'; 217 print <<'(END)';
218<pre><font color="#FF0000">WARNING:</font> 218<pre><font color="#FF0000">WARNING:</font>
219Downloading your file will remove it from the server. If the 219Downloading your file will remove it from the server. If the
220download fails, contact the system administrator, and they may 220download fails, contact the system administrator, and they may
221be able to retrieve the file. 221be able to retrieve the file.
222</pre> 222</pre>
223(END) 223(END)
224 } 224 }
225 225
226 print $q->h2("Download your player file:"); 226 print $q->h2("Download your player file:");
227 227
228 # Print generic form to allow player to download their file. 228 # Print generic form to allow player to download their file.
229 print $q->start_form(), 229 print $q->start_form(),
230 'Character name: ', $q->textfield('playername'), $q->br(), 230 'Character name: ', $q->textfield('playername'), $q->br(),
231 'Character password: ' , $q->password_field('password'), $q->br(), 231 'Character password: ' , $q->password_field('password'), $q->br(),
232 $q->submit('Download'), $q->reset('Clear Entries'), $q->end_form(); 232 $q->submit('Download'), $q->reset('Clear Entries'), $q->end_form();
233 233
234 print $q->end_html(); 234 print $q->end_html();
235} 235}

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines