240
240
"""A representation of a client host served by this server.
243
_approved: bool(); 'None' if not yet approved/disapproved
244
approval_delay: datetime.timedelta(); Time to wait for approval
245
approval_duration: datetime.timedelta(); Duration of one approval
243
name: string; from the config file, used in log messages and
245
fingerprint: string (40 or 32 hexadecimal digits); used to
246
uniquely identify the client
247
secret: bytestring; sent verbatim (over TLS) to client
248
host: string; available for use by the checker command
249
created: datetime.datetime(); (UTC) object creation
250
last_enabled: datetime.datetime(); (UTC)
252
last_checked_ok: datetime.datetime(); (UTC) or None
253
timeout: datetime.timedelta(); How long from last_checked_ok
254
until this client is disabled
255
interval: datetime.timedelta(); How often to start a new checker
256
disable_hook: If set, called by disable() as disable_hook(self)
246
257
checker: subprocess.Popen(); a running checker process used
247
258
to see if the client lives.
248
259
'None' if no process is running.
249
checker_callback_tag: a gobject event source tag, or None
250
checker_command: string; External command which is run to check
251
if client lives. %() expansions are done at
260
checker_initiator_tag: a gobject event source tag, or None
261
disable_initiator_tag: - '' -
262
checker_callback_tag: - '' -
263
checker_command: string; External command which is run to check if
264
client lives. %() expansions are done at
252
265
runtime with vars(self) as dict, so that for
253
266
instance %(name)s can be used in the command.
254
checker_initiator_tag: a gobject event source tag, or None
255
created: datetime.datetime(); (UTC) object creation
256
267
current_checker_command: string; current running checker_command
257
disable_hook: If set, called by disable() as disable_hook(self)
258
disable_initiator_tag: a gobject event source tag, or None
260
fingerprint: string (40 or 32 hexadecimal digits); used to
261
uniquely identify the client
262
host: string; available for use by the checker command
263
interval: datetime.timedelta(); How often to start a new checker
264
last_approval_request: datetime.datetime(); (UTC) or None
265
last_checked_ok: datetime.datetime(); (UTC) or None
266
last_enabled: datetime.datetime(); (UTC)
267
name: string; from the config file, used in log messages and
269
secret: bytestring; sent verbatim (over TLS) to client
270
timeout: datetime.timedelta(); How long from last_checked_ok
271
until this client is disabled
272
runtime_expansions: Allowed attributes for runtime expansion.
268
approval_delay: datetime.timedelta(); Time to wait for approval
269
_approved: bool(); 'None' if not yet approved/disapproved
270
approval_duration: datetime.timedelta(); Duration of one approval
275
runtime_expansions = (u"approval_delay", u"approval_duration",
276
u"created", u"enabled", u"fingerprint",
277
u"host", u"interval", u"last_checked_ok",
278
u"last_enabled", u"name", u"timeout")
281
274
def _timedelta_to_milliseconds(td):
282
275
"Convert a datetime.timedelta() to milliseconds"
728
711
Client.__init__(self, *args, **kwargs)
729
712
# Only now, when this client is initialized, can it show up on
731
client_object_name = unicode(self.name).translate(
732
{ord(u"."): ord(u"_"),
733
ord(u"-"): ord(u"_")})
734
714
self.dbus_object_path = (dbus.ObjectPath
735
(u"/clients/" + client_object_name))
716
+ self.name.replace(u".", u"_")))
736
717
DBusObjectWithProperties.__init__(self, self.bus,
737
718
self.dbus_object_path)
820
801
variant_level=1)))
823
def need_approval(self, *args, **kwargs):
824
r = Client.need_approval(self, *args, **kwargs)
826
self.PropertyChanged(
827
dbus.String(u"LastApprovalRequest"),
828
(self._datetime_to_dbus(self.last_approval_request,
832
804
def start_checker(self, *args, **kwargs):
833
805
old_checker = self.checker
834
806
if self.checker is not None:
1138
1101
class ProxyClient(object):
1139
1102
def __init__(self, child_pipe, fpr, address):
1140
1103
self._pipe = child_pipe
1141
self._pipe.send((u'init', fpr, address))
1104
self._pipe.send(('init', fpr, address))
1142
1105
if not self._pipe.recv():
1143
1106
raise KeyError()
1145
1108
def __getattribute__(self, name):
1146
if(name == u'_pipe'):
1109
if(name == '_pipe'):
1147
1110
return super(ProxyClient, self).__getattribute__(name)
1148
self._pipe.send((u'getattr', name))
1111
self._pipe.send(('getattr', name))
1149
1112
data = self._pipe.recv()
1150
if data[0] == u'data':
1113
if data[0] == 'data':
1152
if data[0] == u'function':
1115
if data[0] == 'function':
1153
1116
def func(*args, **kwargs):
1154
self._pipe.send((u'funcall', name, args, kwargs))
1117
self._pipe.send(('funcall', name, args, kwargs))
1155
1118
return self._pipe.recv()[1]
1158
1121
def __setattr__(self, name, value):
1159
if(name == u'_pipe'):
1122
if(name == '_pipe'):
1160
1123
return super(ProxyClient, self).__setattr__(name, value)
1161
self._pipe.send((u'setattr', name, value))
1124
self._pipe.send(('setattr', name, value))
1164
1127
class ClientHandler(socketserver.BaseRequestHandler, object):
1520
1483
# broken, usually for pipes and
1523
conditions_string = u' | '.join(name
1486
conditions_string = ' | '.join(name
1524
1487
for cond, name in
1525
1488
condition_names.iteritems()
1526
1489
if cond & condition)
1490
logger.debug(u"Handling IPC: FD = %d, condition = %s", source,
1527
1493
# error or the other end of multiprocessing.Pipe has closed
1528
1494
if condition & (gobject.IO_ERR | condition & gobject.IO_HUP):
1531
1497
# Read a request from the child
1532
1498
request = parent_pipe.recv()
1499
logger.debug(u"IPC request: %s", repr(request))
1533
1500
command = request[0]
1535
if command == u'init':
1502
if command == 'init':
1536
1503
fpr = request[1]
1537
1504
address = request[2]
1557
1524
parent_pipe.send(True)
1558
1525
# remove the old hook in favor of the new above hook on same fileno
1560
if command == u'funcall':
1527
if command == 'funcall':
1561
1528
funcname = request[1]
1562
1529
args = request[2]
1563
1530
kwargs = request[3]
1565
parent_pipe.send((u'data', getattr(client_object, funcname)(*args, **kwargs)))
1532
parent_pipe.send(('data', getattr(client_object, funcname)(*args, **kwargs)))
1567
if command == u'getattr':
1534
if command == 'getattr':
1568
1535
attrname = request[1]
1569
1536
if callable(client_object.__getattribute__(attrname)):
1570
parent_pipe.send((u'function',))
1537
parent_pipe.send(('function',))
1572
parent_pipe.send((u'data', client_object.__getattribute__(attrname)))
1539
parent_pipe.send(('data', client_object.__getattribute__(attrname)))
1574
if command == u'setattr':
1541
if command == 'setattr':
1575
1542
attrname = request[1]
1576
1543
value = request[2]
1577
1544
setattr(client_object, attrname, value)
1672
1639
##################################################################
1673
1640
# Parsing of options, both command line and config file
1675
parser = optparse.OptionParser(version = u"%%prog %s" % version)
1676
parser.add_option(u"-i", u"--interface", type=u"string",
1677
metavar=u"IF", help=u"Bind to interface IF")
1678
parser.add_option(u"-a", u"--address", type=u"string",
1642
parser = optparse.OptionParser(version = "%%prog %s" % version)
1643
parser.add_option("-i", u"--interface", type=u"string",
1644
metavar="IF", help=u"Bind to interface IF")
1645
parser.add_option("-a", u"--address", type=u"string",
1679
1646
help=u"Address to listen for requests on")
1680
parser.add_option(u"-p", u"--port", type=u"int",
1647
parser.add_option("-p", u"--port", type=u"int",
1681
1648
help=u"Port number to receive requests on")
1682
parser.add_option(u"--check", action=u"store_true",
1649
parser.add_option("--check", action=u"store_true",
1683
1650
help=u"Run self-test")
1684
parser.add_option(u"--debug", action=u"store_true",
1651
parser.add_option("--debug", action=u"store_true",
1685
1652
help=u"Debug mode; run in foreground and log to"
1687
parser.add_option(u"--debuglevel", type=u"string", metavar="LEVEL",
1654
parser.add_option("--debuglevel", type=u"string", metavar="Level",
1688
1655
help=u"Debug level for stdout output")
1689
parser.add_option(u"--priority", type=u"string", help=u"GnuTLS"
1656
parser.add_option("--priority", type=u"string", help=u"GnuTLS"
1690
1657
u" priority string (see GnuTLS documentation)")
1691
parser.add_option(u"--servicename", type=u"string",
1658
parser.add_option("--servicename", type=u"string",
1692
1659
metavar=u"NAME", help=u"Zeroconf service name")
1693
parser.add_option(u"--configdir", type=u"string",
1660
parser.add_option("--configdir", type=u"string",
1694
1661
default=u"/etc/mandos", metavar=u"DIR",
1695
1662
help=u"Directory to search for configuration"
1697
parser.add_option(u"--no-dbus", action=u"store_false",
1664
parser.add_option("--no-dbus", action=u"store_false",
1698
1665
dest=u"use_dbus", help=u"Do not provide D-Bus"
1699
1666
u" system bus interface")
1700
parser.add_option(u"--no-ipv6", action=u"store_false",
1667
parser.add_option("--no-ipv6", action=u"store_false",
1701
1668
dest=u"use_ipv6", help=u"Do not use IPv6")
1702
1669
options = parser.parse_args()[0]
1788
1755
gnutls_priority=
1789
1756
server_settings[u"priority"],
1790
1757
use_dbus=use_dbus)
1792
pidfilename = u"/var/run/mandos.pid"
1794
pidfile = open(pidfilename, u"w")
1796
logger.error(u"Could not open file %r", pidfilename)
1758
pidfilename = u"/var/run/mandos.pid"
1760
pidfile = open(pidfilename, u"w")
1762
logger.error(u"Could not open file %r", pidfilename)
1799
1765
uid = pwd.getpwnam(u"_mandos").pw_uid
1871
1833
service = AvahiService(name = server_settings[u"servicename"],
1872
1834
servicetype = u"_mandos._tcp",
1873
1835
protocol = protocol, bus = bus)
1874
if server_settings[u"interface"]:
1836
if server_settings["interface"]:
1875
1837
service.interface = (if_nametoindex
1876
1838
(str(server_settings[u"interface"])))
1841
# Close all input and output, do double fork, etc.
1878
1844
global multiprocessing_manager
1879
1845
multiprocessing_manager = multiprocessing.Manager()
1901
1867
if not tcp_server.clients:
1902
1868
logger.warning(u"No clients defined")
1873
pidfile.write(str(pid) + "\n")
1876
logger.error(u"Could not write to file %r with PID %d",
1879
# "pidfile" was never created
1908
pidfile.write(str(pid) + u"\n".encode("utf-8"))
1911
logger.error(u"Could not write to file %r with PID %d",
1914
# "pidfile" was never created
1918
1884
signal.signal(signal.SIGINT, signal.SIG_IGN)
1920
1885
signal.signal(signal.SIGHUP, lambda signum, frame: sys.exit())
1921
1886
signal.signal(signal.SIGTERM, lambda signum, frame: sys.exit())