fix a few bogus dates in specfile
[sfa.git] / flashpolicy / sfa_flashpolicy.py
1 #!/usr/bin/env python
2 #
3 # flashpolicyd.py
4 # Simple socket policy file server for Flash
5 #
6 # Usage: flashpolicyd.py [--port=N] --file=FILE
7 #
8 # Logs to stderr
9 # Requires Python 2.5 or later
10
11 from __future__ import with_statement
12 import os
13 import sys
14 import optparse
15 import socket
16 import thread
17 import exceptions
18 import contextlib
19
20 VERSION = 0.1
21
22
23 def daemon():
24     """Daemonize the current process."""
25     if os.fork() != 0:
26         os._exit(0)
27     os.setsid()
28     if os.fork() != 0:
29         os._exit(0)
30     os.umask(0)
31     devnull = os.open(os.devnull, os.O_RDWR)
32     os.dup2(devnull, 0)
33     # xxx fixme - this is just to make sure that nothing gets stupidly lost -
34     # should use devnull
35     crashlog = os.open('/var/log/sfa_flashpolicy.log', os.O_RDWR | os.O_APPEND | os.O_CREAT, 0644)
36     os.dup2(crashlog, 1)
37     os.dup2(crashlog, 2)
38
39
40 class policy_server(object):
41
42     def __init__(self, port, path):
43         self.port = port
44         self.path = path
45         self.policy = self.read_policy(path)
46         self.log('Listening on port %d\n' % port)
47         try:
48             self.sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
49         except AttributeError:
50             # AttributeError catches Python built without IPv6
51             self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
52         except socket.error:
53             # socket.error catches OS with IPv6 disabled
54             self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
55         self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
56         self.sock.bind(('', port))
57         self.sock.listen(5)
58
59     def read_policy(self, path):
60         with open(path, 'rb') as f:
61             policy = f.read(10001)
62             if len(policy) > 10000:
63                 raise exceptions.RuntimeError('File probably too large to be a policy file',
64                                               path)
65             if 'cross-domain-policy' not in policy:
66                 raise exceptions.RuntimeError('Not a valid policy file',
67                                               path)
68             return policy
69
70     def run(self):
71         try:
72             while True:
73                 thread.start_new_thread(self.handle, self.sock.accept())
74         except socket.error as e:
75             self.log('Error accepting connection: %s' % e[1])
76
77     def handle(self, conn, addr):
78         addrstr = '%s:%s' % (addr[0], addr[1])
79         try:
80             self.log('Connection from %s' % addrstr)
81             with contextlib.closing(conn):
82                 # It's possible that we won't get the entire request in
83                 # a single recv, but very unlikely.
84                 request = conn.recv(1024).strip()
85                 # if request != '<policy-file-request/>\0':
86                 #    self.log('Unrecognized request from %s: %s' % (addrstr, request))
87                 #    return
88                 self.log('Valid request received from %s' % addrstr)
89                 conn.sendall(self.policy)
90                 self.log('Sent policy file to %s' % addrstr)
91         except socket.error as e:
92             self.log('Error handling connection from %s: %s' % (addrstr, e[1]))
93         except Exception as e:
94             self.log('Error handling connection from %s: %s' % (addrstr, e[1]))
95
96     def log(self, str):
97         print >>sys.stderr, str
98
99
100 def main():
101     parser = optparse.OptionParser(usage='%prog [--port=PORT] --file=FILE',
102                                    version='%prog ' + str(VERSION))
103     parser.add_option('-p', '--port', dest='port', type=int, default=843,
104                       help='listen on port PORT', metavar='PORT')
105     parser.add_option('-f', '--file', dest='path',
106                       help='server policy file FILE', metavar='FILE')
107     parser.add_option("-d", "--daemon", dest="daemon", action="store_true",
108                       help="Run as daemon.", default=False)
109     opts, args = parser.parse_args()
110     if args:
111         parser.error('No arguments are needed. See help.')
112     if not opts.path:
113         parser.error('File must be specified. See help.')
114
115     try:
116         if opts.daemon:
117             daemon()
118         policy_server(opts.port, opts.path).run()
119     except Exception as e:
120         print >> sys.stderr, e
121         sys.exit(1)
122     except KeyboardInterrupt:
123         pass
124
125 if __name__ == '__main__':
126     main()