3 # CGI for stream exchange
5 # Author: Ulli Horlacher <framstag@rus.uni-stuttgart.de>
7 use Fcntl qw':flock :seek :mode';
9 use Digest::MD5 qw'md5_hex';
12 (our $FEXLIB) = $ENV{FEXLIB} =~ /(.+)/;
13 die "$0: no $FEXLIB\n" unless -d $FEXLIB;
18 our ($tmpdir,@logdir,$timeout,$fra,$bs);
20 # load common code, local config: $HOME/lib/fex.ph
21 require "$FEXLIB/fex.pp" or die "$0: cannot load $FEXLIB/fex.pp - $!\n";
23 chdir $spooldir or error(500,"$spooldir - $!");
25 # my $debuglog = "$tmpdir/sex.log";
26 my $ra = $ENV{REMOTE_ADDR}||0;
27 $fra .= '/'.$ENV{HTTP_X_FORWARDED_FOR} if $ENV{HTTP_X_FORWARDED_FOR};
31 # in normal mode the recipient needs authentification, not the sender
32 # in public mode the sender needs authentification, not the recipient
34 $user = $id = $pmode = $type = '';
36 $mode = $ENV{REQUEST_METHOD} eq 'POST' ? 'PUSH' : 'POP';
38 # parse HTTP QUERY_STRING
39 if (my $qs = $ENV{QUERY_STRING}) {
40 $qs = decode_b64($qs) if $qs =~ /^\w+=*$/;
41 foreach (split '&',$qs) { setparam(split '=',"$_=") };
44 unless ($user) { error(400,"Missing user") }
45 if ($mdomain and $user !~ /@/) { $user .= '@'.$mdomain }
46 if ($user =~ /^anonymous/) {
47 if (@anonymous_upload and ipin($ra,@anonymous_upload)) {
50 error(403,"Forbidden");
53 unless (-f "$user/@") { error(404,"Unknown user $user") }
55 chdir $user or error(500,"$user - $!");
57 $stream = "STREAM/$stream";
59 if ($mode eq 'PUSH') {
60 if ($pmode eq 'PUBLIC') {
62 $stream =~ s:/STDSTR:/PUBLIC:;
65 my $fifo = "$stream/fifo";
67 mkfifo($fifo,0600) or error(503,"Cannot create $fifo : $!");
72 my $lock = "$stream/lock";
73 open $lock,'>>',$lock or error(503,"Cannot open $lock : $!");
74 flock $lock,LOCK_EX|LOCK_NB or error(409,"$stream already in use");
77 unlink "$stream/mode";
78 unlink "$stream/type";
79 symlink $pmode,"$stream/mode" if $pmode;
80 symlink $type, "$stream/type" if $type;
92 syswrite STDOUT,"HTTP/1.9 199 Hold on";
93 for (my $i=0;$i<$timeout;$i++) {
96 # will hang until $stream is opend for reading by another process
97 open $fifo,'>',$fifo and last;
98 unless ($ALARM) { error(503,"Cannot open $fifo : $!") }
101 syswrite STDOUT,"\r\n";
103 unless (fileno $fifo) {
105 error(504,"Timeout");
111 $shutdown = sub { sexlog($B); rmrf($stream); exit; };
112 $SIG{PIPE} = sub { sleep 1; &$shutdown; };
113 # syswrite $fifo,$data if $data;
114 while ($b = sysread(STDIN,$_,$bs)) {
116 syswrite $fifo,$_ or die $!;
121 elsif ($mode eq 'POP') {
122 $stream =~ s:/STDSTR:/PUBLIC: if $id eq 'public';
123 unless ($id eq 'public' and (readlink "$stream/mode"||'') eq 'PUBLIC'
124 or $user =~ /^anonymous/) {
127 error(503,"No $stream for $user") unless -d $stream;
128 $type = readlink "$stream/type" || '';
129 $SIG{ALRM} = sub { error(504,"Timeout") };
131 my $fifo = "$stream/fifo";
132 if (-e $fifo and not -r $fifo) { error(503,"$stream already in use") }
133 open $fifo,'<',$fifo or error(503,"Cannot open $fifo : $!");
136 header('200 OK',$type);
139 while (sysread($fifo,$_,$bs)) {
140 syswrite STDOUT,$_ or die $!;
147 error(405,"Unknown Request");
156 $v = uc(despace($v));
157 $vv = untaint(normalize($vv));
159 if ($v eq 'USER') { $user = lc(despace($vv)) }
160 elsif ($v eq 'ID') { $id = despace($vv) }
161 elsif ($v eq 'MODE') { $pmode = uc(despace($vv)) }
162 elsif ($v eq 'TYPE') { $type = uc(despace($vv)) }
163 elsif ($v eq 'STREAM') { $stream = normalize_filename($vv) }
164 elsif ($v eq 'BS' and $vv =~ /(\d+)/) { $bs = $1 }
165 elsif ($v eq 'TIMEOUT' and $vv =~ /(\d+)/) { $timeout = $1 }
166 elsif ($v eq 'ANONYMOUS') { $id = $user ='anonymous'; $stream = $vv; }
174 $msg = sprintf "%s [%s_%s] %s (%s) %s\n",
175 isodate(time),$$,$ENV{REQUESTCOUNT},$user,$fra,$msg;
177 foreach my $log (@logdir) {
178 if (open $log,'>>',"$log/sex.log") {
180 seek $log,0,SEEK_END;
199 $msg = sprintf "%s %s (%s) caught SIGNAL %s\n",
200 isodate(time),$user||'-',$fra||'-',$msg;
202 foreach my $log (@logdir) {
203 if (open $log,'>>',"$log/sex.log") {
205 seek $log,0,SEEK_END;
219 nvt_print("HTTP/1.1 @_");
224 my ($status,$type) = @_;
226 return if $HTTP_HEADER;
227 $HTTP_HEADER = $status;
229 nvt_print("HTTP/1.1 $status");
230 if ($mode eq 'POP') {
231 nvt_print("Server: sexsrv");
232 if ($type eq 'GZIP') {
233 nvt_print("Content-Type: application/gzip");
235 nvt_print("Content-Type: application/binary");
237 nvt_print("Expires: 0");
238 nvt_print("Cache-Control: no-cache");
239 nvt_print("Connection: close");
247 error(400,"Missing auth-ID") unless $id;
248 open $id,'<','@' or error(401,"$user/@ - $!");
249 chomp($rid = <$id>||'');
251 if ($rid and $sid and $id =~ /^(MD5H:)/) {
252 $rid = $1 . md5_hex($rid.$sid);
254 error(401,"Wrong auth-ID") if $rid ne $id;