133
133
u" retries, exiting.", rename_count)
134
134
raise AvahiServiceError("Too many renames")
135
135
name = server.GetAlternativeServiceName(name)
136
logger.error(u"Changing name to %r ...", name)
136
logger.notice(u"Changing name to %r ...", name)
139
139
self.rename_count += 1
221
221
interval = property(lambda self: self._interval,
223
223
del _set_interval
224
def __init__(self, name = None, stop_hook=None, config={}):
224
def __init__(self, name=None, stop_hook=None, fingerprint=None,
225
secret=None, secfile=None, fqdn=None, timeout=None,
226
interval=-1, checker=None):
225
227
"""Note: the 'checker' argument sets the 'checker_command'
226
228
attribute and not the 'checker' attribute.."""
229
231
# Uppercase and remove spaces from fingerprint
230
232
# for later comparison purposes with return value of
231
233
# the fingerprint() function
232
self.fingerprint = config["fingerprint"].upper()\
234
self.fingerprint = fingerprint.upper().replace(u" ", u"")
234
235
logger.debug(u" Fingerprint: %s", self.fingerprint)
235
if "secret" in config:
236
self.secret = config["secret"].decode(u"base64")
237
elif "secfile" in config:
238
sf = open(config["secfile"])
237
self.secret = secret.decode(u"base64")
239
240
self.secret = sf.read()
242
243
raise TypeError(u"No secret or secfile for client %s"
244
self.fqdn = config.get("fqdn", "")
245
246
self.created = datetime.datetime.now()
246
247
self.last_checked_ok = None
247
self.timeout = string_to_delta(config["timeout"])
248
self.interval = string_to_delta(config["interval"])
248
self.timeout = string_to_delta(timeout)
249
self.interval = string_to_delta(interval)
249
250
self.stop_hook = stop_hook
250
251
self.checker = None
251
252
self.checker_initiator_tag = None
252
253
self.stop_initiator_tag = None
253
254
self.checker_callback_tag = None
254
self.check_command = config["checker"]
255
self.check_command = checker
256
257
"""Start this client's checker and timeout hooks"""
257
258
# Schedule a new checker to be started an 'interval' from now,
271
272
but not currently used."""
272
273
# If this client doesn't have a secret, it is already stopped.
274
logger.info(u"Stopping client %s", self.name)
275
logger.debug(u"Stopping client %s", self.name)
275
276
self.secret = None
296
297
self.checker = None
297
298
if os.WIFEXITED(condition) \
298
299
and (os.WEXITSTATUS(condition) == 0):
299
logger.info(u"Checker for %(name)s succeeded",
300
logger.debug(u"Checker for %(name)s succeeded",
301
302
self.last_checked_ok = now
302
303
gobject.source_remove(self.stop_initiator_tag)
303
304
self.stop_initiator_tag = gobject.timeout_add\
307
308
logger.warning(u"Checker for %(name)s crashed?",
310
logger.info(u"Checker for %(name)s failed",
311
logger.debug(u"Checker for %(name)s failed",
312
313
def start_checker(self):
313
314
"""Start a new checker subprocess if one is not running.
314
315
If a checker already exists, leave it running and do
337
338
u' %s', self.check_command, error)
338
339
return True # Try again later
340
logger.info(u"Starting checker %r for %s",
341
logger.debug(u"Starting checker %r for %s",
342
343
self.checker = subprocess.Popen(command,
344
345
shell=True, cwd="/")
430
431
Note: This will run in its own forked process."""
432
433
def handle(self):
433
logger.info(u"TCP connection from: %s",
434
logger.debug(u"TCP connection from: %s",
434
435
unicode(self.client_address))
435
436
session = gnutls.connection.ClientSession\
436
437
(self.request, gnutls.connection.X509Credentials())
438
line = self.request.makefile().readline()
439
logger.debug(u"Protocol version: %r", line)
441
if int(line.strip().split()[0]) > 1:
443
except (ValueError, IndexError, RuntimeError), error:
444
logger.error(u"Unknown protocol version: %s", error)
447
438
# Note: gnutls.connection.X509Credentials is really a generic
448
439
# GnuTLS certificate credentials object so long as no X.509
449
440
# keys are added to it. Therefore, we can use it here despite
463
454
session.handshake()
464
455
except gnutls.errors.GNUTLSError, error:
465
logger.warning(u"Handshake failed: %s", error)
456
logger.debug(u"Handshake failed: %s", error)
466
457
# Do not run session.bye() here: the session is not
467
458
# established. Just abandon the request.
470
461
fpr = fingerprint(peer_certificate(session))
471
462
except (TypeError, gnutls.errors.GNUTLSError), error:
472
logger.warning(u"Bad certificate: %s", error)
463
logger.debug(u"Bad certificate: %s", error)
475
466
logger.debug(u"Fingerprint: %s", fpr)
482
logger.warning(u"Client not found for fingerprint: %s",
473
logger.debug(u"Client not found for fingerprint: %s", fpr)
486
476
# Have to check if client.still_valid(), since it is possible
487
477
# that the client timed out while establishing the GnuTLS
489
479
if not client.still_valid():
490
logger.warning(u"Client %(name)s is invalid",
480
logger.debug(u"Client %(name)s is invalid", vars(client))
520
509
"""This overrides the normal server_bind() function
521
510
to bind to an interface if one was specified, and also NOT to
522
511
bind to an address or port if they were not specified."""
523
if self.settings["interface"]:
512
if self.settings["interface"] != avahi.IF_UNSPEC:
524
513
# 25 is from /usr/include/asm-i486/socket.h
525
514
SO_BINDTODEVICE = getattr(socket, "SO_BINDTODEVICE", 25)
529
518
self.settings["interface"])
530
519
except socket.error, error:
531
520
if error[0] == errno.EPERM:
532
logger.error(u"No permission to"
533
u" bind to interface %s",
534
self.settings["interface"])
521
logger.warning(u"No permission to"
522
u" bind to interface %s",
523
self.settings["interface"])
537
526
# Only bind(2) the socket if we really need to.
583
572
def server_state_changed(state):
584
573
"""Derived from the Avahi example code"""
585
574
if state == avahi.SERVER_COLLISION:
586
logger.error(u"Server name collision")
575
logger.warning(u"Server name collision")
588
577
elif state == avahi.SERVER_RUNNING:
604
593
raise AvahiGroupError("State changed: %s", str(error))
606
def if_nametoindex(interface):
595
def if_nametoindex(interface, _func=[None]):
607
596
"""Call the C function if_nametoindex(), or equivalent"""
608
global if_nametoindex
597
if _func[0] is not None:
598
return _func[0](interface)
610
600
if "ctypes.util" not in sys.modules:
611
601
import ctypes.util
612
if_nametoindex = ctypes.cdll.LoadLibrary\
613
(ctypes.util.find_library("c")).if_nametoindex
604
libc = ctypes.cdll.LoadLibrary\
605
(ctypes.util.find_library("c"))
606
func[0] = libc.if_nametoindex
607
return _func[0](interface)
614
611
except (OSError, AttributeError):
615
612
if "struct" not in sys.modules:
617
614
if "fcntl" not in sys.modules:
619
def if_nametoindex(interface):
616
def the_hard_way(interface):
620
617
"Get an interface index the hard way, i.e. using fcntl()"
621
618
SIOCGIFINDEX = 0x8933 # From /usr/include/linux/sockios.h
622
619
s = socket.socket()
626
623
interface_index = struct.unpack("I", ifreq[16:20])[0]
627
624
return interface_index
628
return if_nametoindex(interface)
625
_func[0] = the_hard_way
626
return _func[0](interface)
631
629
def daemon(nochdir, noclose):
701
699
server_settings["debug"] = server_config.getboolean\
702
700
(server_section, "debug")
703
701
del server_config
702
if not server_settings["interface"]:
703
server_settings["interface"] = avahi.IF_UNSPEC
705
705
# Override the settings from the config file with command line
706
706
# options, if set.
725
725
service = AvahiService(name = server_settings["servicename"],
726
726
type = "_mandos._tcp", );
727
if server_settings["interface"]:
728
service.interface = if_nametoindex(server_settings["interface"])
753
751
def remove_from_clients(client):
754
752
clients.remove(client)
756
logger.critical(u"No clients left, exiting")
754
logger.debug(u"No clients left, exiting")
759
clients.update(Set(Client(name = section,
757
clients.update(Set(Client(name=section,
760
758
stop_hook = remove_from_clients,
762
= dict(client_config.items(section)))
759
**(dict(client_config\
763
761
for section in client_config.sections()))
797
795
# Find out what port we got
798
796
service.port = tcp_server.socket.getsockname()[1]
799
logger.info(u"Now listening on address %r, port %d, flowinfo %d,"
800
u" scope_id %d" % tcp_server.socket.getsockname())
797
logger.debug(u"Now listening on port %d", service.port)
802
#service.interface = tcp_server.socket.getsockname()[3]
799
if not server_settings["interface"]:
800
service.interface = if_nametoindex\
801
(server_settings["interface"])
805
804
# From the Avahi example code