/mandos/trunk

To get this branch, use:
bzr branch http://bzr.recompile.se/loggerhead/mandos/trunk

« back to all changes in this revision

Viewing changes to mandos

  • Committer: Teddy Hogeborn
  • Date: 2011-07-25 18:52:11 UTC
  • mfrom: (489 trunk)
  • mto: (237.4.29 release)
  • mto: This revision was merged to the branch mainline in revision 490.
  • Revision ID: teddy@fukt.bsnet.se-20110725185211-wlitr9jvs70e1xh8
MergeĀ fromĀ trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
36
36
 
37
37
import SocketServer as socketserver
38
38
import socket
39
 
import optparse
 
39
import argparse
40
40
import datetime
41
41
import errno
42
42
import gnutls.crypto
151
151
        self.group = None       # our entry group
152
152
        self.server = None
153
153
        self.bus = bus
 
154
        self.entry_group_state_changed_match = None
154
155
    def rename(self):
155
156
        """Derived from the Avahi example code"""
156
157
        if self.rename_count >= self.max_renames:
168
169
        self.remove()
169
170
        try:
170
171
            self.add()
171
 
        except dbus.exceptions.DBusException, error:
 
172
        except dbus.exceptions.DBusException as error:
172
173
            logger.critical("DBusException: %s", error)
173
174
            self.cleanup()
174
175
            os._exit(1)
175
176
        self.rename_count += 1
176
177
    def remove(self):
177
178
        """Derived from the Avahi example code"""
 
179
        if self.entry_group_state_changed_match is not None:
 
180
            self.entry_group_state_changed_match.remove()
 
181
            self.entry_group_state_changed_match = None
178
182
        if self.group is not None:
179
183
            self.group.Reset()
180
184
    def add(self):
181
185
        """Derived from the Avahi example code"""
 
186
        self.remove()
182
187
        if self.group is None:
183
188
            self.group = dbus.Interface(
184
189
                self.bus.get_object(avahi.DBUS_NAME,
185
190
                                    self.server.EntryGroupNew()),
186
191
                avahi.DBUS_INTERFACE_ENTRY_GROUP)
187
 
            self.group.connect_to_signal('StateChanged',
188
 
                                         self
189
 
                                         .entry_group_state_changed)
 
192
        self.entry_group_state_changed_match = (
 
193
            self.group.connect_to_signal(
 
194
                'StateChanged', self .entry_group_state_changed))
190
195
        logger.debug("Adding Zeroconf service '%s' of type '%s' ...",
191
196
                     self.name, self.type)
192
197
        self.group.AddService(
215
220
    def cleanup(self):
216
221
        """Derived from the Avahi example code"""
217
222
        if self.group is not None:
218
 
            self.group.Free()
 
223
            try:
 
224
                self.group.Free()
 
225
            except (dbus.exceptions.UnknownMethodException,
 
226
                    dbus.exceptions.DBusException) as e:
 
227
                pass
219
228
            self.group = None
220
 
    def server_state_changed(self, state):
 
229
        self.remove()
 
230
    def server_state_changed(self, state, error=None):
221
231
        """Derived from the Avahi example code"""
222
232
        logger.debug("Avahi server state change: %i", state)
223
 
        if state == avahi.SERVER_COLLISION:
224
 
            logger.error("Zeroconf server name collision")
225
 
            self.remove()
 
233
        bad_states = { avahi.SERVER_INVALID:
 
234
                           "Zeroconf server invalid",
 
235
                       avahi.SERVER_REGISTERING: None,
 
236
                       avahi.SERVER_COLLISION:
 
237
                           "Zeroconf server name collision",
 
238
                       avahi.SERVER_FAILURE:
 
239
                           "Zeroconf server failure" }
 
240
        if state in bad_states:
 
241
            if bad_states[state] is not None:
 
242
                if error is None:
 
243
                    logger.error(bad_states[state])
 
244
                else:
 
245
                    logger.error(bad_states[state] + ": %r", error)
 
246
            self.cleanup()
226
247
        elif state == avahi.SERVER_RUNNING:
227
248
            self.add()
 
249
        else:
 
250
            if error is None:
 
251
                logger.debug("Unknown state: %r", state)
 
252
            else:
 
253
                logger.debug("Unknown state: %r: %r", state, error)
228
254
    def activate(self):
229
255
        """Derived from the Avahi example code"""
230
256
        if self.server is None:
231
257
            self.server = dbus.Interface(
232
258
                self.bus.get_object(avahi.DBUS_NAME,
233
 
                                    avahi.DBUS_PATH_SERVER),
 
259
                                    avahi.DBUS_PATH_SERVER,
 
260
                                    follow_name_owner_changes=True),
234
261
                avahi.DBUS_INTERFACE_SERVER)
235
262
        self.server.connect_to_signal("StateChanged",
236
263
                                 self.server_state_changed)
445
472
        # If a checker exists, make sure it is not a zombie
446
473
        try:
447
474
            pid, status = os.waitpid(self.checker.pid, os.WNOHANG)
448
 
        except (AttributeError, OSError), error:
 
475
        except (AttributeError, OSError) as error:
449
476
            if (isinstance(error, OSError)
450
477
                and error.errno != errno.ECHILD):
451
478
                raise error
472
499
 
473
500
                try:
474
501
                    command = self.checker_command % escaped_attrs
475
 
                except TypeError, error:
 
502
                except TypeError as error:
476
503
                    logger.error('Could not format string "%s":'
477
504
                                 ' %s', self.checker_command, error)
478
505
                    return True # Try again later
497
524
                if pid:
498
525
                    gobject.source_remove(self.checker_callback_tag)
499
526
                    self.checker_callback(pid, status, command)
500
 
            except OSError, error:
 
527
            except OSError as error:
501
528
                logger.error("Failed to start subprocess: %s",
502
529
                             error)
503
530
        # Re-run this periodically if run by gobject.timeout_add
516
543
            #time.sleep(0.5)
517
544
            #if self.checker.poll() is None:
518
545
            #    os.kill(self.checker.pid, signal.SIGKILL)
519
 
        except OSError, error:
 
546
        except OSError as error:
520
547
            if error.errno != errno.ESRCH: # No such process
521
548
                raise
522
549
        self.checker = None
704
731
            xmlstring = document.toxml("utf-8")
705
732
            document.unlink()
706
733
        except (AttributeError, xml.dom.DOMException,
707
 
                xml.parsers.expat.ExpatError), error:
 
734
                xml.parsers.expat.ExpatError) as error:
708
735
            logger.error("Failed to override Introspection method",
709
736
                         error)
710
737
        return xmlstring
813
840
                                       *args, **kwargs)
814
841
    
815
842
    def checked_ok(self, *args, **kwargs):
816
 
        r = Client.checked_ok(self, *args, **kwargs)
 
843
        Client.checked_ok(self, *args, **kwargs)
817
844
        # Emit D-Bus signal
818
845
        self.PropertyChanged(
819
846
            dbus.String("LastCheckedOK"),
820
847
            (self._datetime_to_dbus(self.last_checked_ok,
821
848
                                    variant_level=1)))
822
 
        return r
823
849
    
824
850
    def need_approval(self, *args, **kwargs):
825
851
        r = Client.need_approval(self, *args, **kwargs)
922
948
    # CheckedOK - method
923
949
    @dbus.service.method(_interface)
924
950
    def CheckedOK(self):
925
 
        return self.checked_ok()
 
951
        self.checked_ok()
926
952
    
927
953
    # Enable - method
928
954
    @dbus.service.method(_interface)
1204
1230
            try:
1205
1231
                if int(line.strip().split()[0]) > 1:
1206
1232
                    raise RuntimeError
1207
 
            except (ValueError, IndexError, RuntimeError), error:
 
1233
            except (ValueError, IndexError, RuntimeError) as error:
1208
1234
                logger.error("Unknown protocol version: %s", error)
1209
1235
                return
1210
1236
 
1211
1237
            # Start GnuTLS connection
1212
1238
            try:
1213
1239
                session.handshake()
1214
 
            except gnutls.errors.GNUTLSError, error:
 
1240
            except gnutls.errors.GNUTLSError as error:
1215
1241
                logger.warning("Handshake failed: %s", error)
1216
1242
                # Do not run session.bye() here: the session is not
1217
1243
                # established.  Just abandon the request.
1223
1249
                try:
1224
1250
                    fpr = self.fingerprint(self.peer_certificate
1225
1251
                                           (session))
1226
 
                except (TypeError, gnutls.errors.GNUTLSError), error:
 
1252
                except (TypeError,
 
1253
                        gnutls.errors.GNUTLSError) as error:
1227
1254
                    logger.warning("Bad certificate: %s", error)
1228
1255
                    return
1229
1256
                logger.debug("Fingerprint: %s", fpr)
1241
1268
                
1242
1269
                while True:
1243
1270
                    if not client.enabled:
1244
 
                        logger.warning("Client %s is disabled",
 
1271
                        logger.info("Client %s is disabled",
1245
1272
                                       client.name)
1246
1273
                        if self.server.use_dbus:
1247
1274
                            # Emit D-Bus signal
1292
1319
                while sent_size < len(client.secret):
1293
1320
                    try:
1294
1321
                        sent = session.send(client.secret[sent_size:])
1295
 
                    except (gnutls.errors.GNUTLSError), error:
 
1322
                    except gnutls.errors.GNUTLSError as error:
1296
1323
                        logger.warning("gnutls send failed")
1297
1324
                        return
1298
1325
                    logger.debug("Sent: %d, remaining: %d",
1312
1339
                    client.approvals_pending -= 1
1313
1340
                try:
1314
1341
                    session.bye()
1315
 
                except (gnutls.errors.GNUTLSError), error:
 
1342
                except gnutls.errors.GNUTLSError as error:
1316
1343
                    logger.warning("GnuTLS bye failed")
1317
1344
    
1318
1345
    @staticmethod
1442
1469
                                           SO_BINDTODEVICE,
1443
1470
                                           str(self.interface
1444
1471
                                               + '\0'))
1445
 
                except socket.error, error:
 
1472
                except socket.error as error:
1446
1473
                    if error[0] == errno.EPERM:
1447
1474
                        logger.error("No permission to"
1448
1475
                                     " bind to interface %s",
1542
1569
                    client = c
1543
1570
                    break
1544
1571
            else:
1545
 
                logger.warning("Client not found for fingerprint: %s, ad"
1546
 
                               "dress: %s", fpr, address)
 
1572
                logger.info("Client not found for fingerprint: %s, ad"
 
1573
                            "dress: %s", fpr, address)
1547
1574
                if self.use_dbus:
1548
1575
                    # Emit D-Bus signal
1549
1576
                    mandos_dbus_service.ClientNotFound(fpr, address[0])
1613
1640
                delta = datetime.timedelta(0, 0, 0, 0, 0, 0, value)
1614
1641
            else:
1615
1642
                raise ValueError("Unknown suffix %r" % suffix)
1616
 
        except (ValueError, IndexError), e:
 
1643
        except (ValueError, IndexError) as e:
1617
1644
            raise ValueError(*(e.args))
1618
1645
        timevalue += delta
1619
1646
    return timevalue
1673
1700
    ##################################################################
1674
1701
    # Parsing of options, both command line and config file
1675
1702
    
1676
 
    parser = optparse.OptionParser(version = "%%prog %s" % version)
1677
 
    parser.add_option("-i", "--interface", type="string",
1678
 
                      metavar="IF", help="Bind to interface IF")
1679
 
    parser.add_option("-a", "--address", type="string",
1680
 
                      help="Address to listen for requests on")
1681
 
    parser.add_option("-p", "--port", type="int",
1682
 
                      help="Port number to receive requests on")
1683
 
    parser.add_option("--check", action="store_true",
1684
 
                      help="Run self-test")
1685
 
    parser.add_option("--debug", action="store_true",
1686
 
                      help="Debug mode; run in foreground and log to"
1687
 
                      " terminal")
1688
 
    parser.add_option("--debuglevel", type="string", metavar="LEVEL",
1689
 
                      help="Debug level for stdout output")
1690
 
    parser.add_option("--priority", type="string", help="GnuTLS"
1691
 
                      " priority string (see GnuTLS documentation)")
1692
 
    parser.add_option("--servicename", type="string",
1693
 
                      metavar="NAME", help="Zeroconf service name")
1694
 
    parser.add_option("--configdir", type="string",
1695
 
                      default="/etc/mandos", metavar="DIR",
1696
 
                      help="Directory to search for configuration"
1697
 
                      " files")
1698
 
    parser.add_option("--no-dbus", action="store_false",
1699
 
                      dest="use_dbus", help="Do not provide D-Bus"
1700
 
                      " system bus interface")
1701
 
    parser.add_option("--no-ipv6", action="store_false",
1702
 
                      dest="use_ipv6", help="Do not use IPv6")
1703
 
    options = parser.parse_args()[0]
 
1703
    parser = argparse.ArgumentParser()
 
1704
    parser.add_argument("-v", "--version", action="version",
 
1705
                        version = "%%(prog)s %s" % version,
 
1706
                        help="show version number and exit")
 
1707
    parser.add_argument("-i", "--interface", metavar="IF",
 
1708
                        help="Bind to interface IF")
 
1709
    parser.add_argument("-a", "--address",
 
1710
                        help="Address to listen for requests on")
 
1711
    parser.add_argument("-p", "--port", type=int,
 
1712
                        help="Port number to receive requests on")
 
1713
    parser.add_argument("--check", action="store_true",
 
1714
                        help="Run self-test")
 
1715
    parser.add_argument("--debug", action="store_true",
 
1716
                        help="Debug mode; run in foreground and log"
 
1717
                        " to terminal")
 
1718
    parser.add_argument("--debuglevel", metavar="LEVEL",
 
1719
                        help="Debug level for stdout output")
 
1720
    parser.add_argument("--priority", help="GnuTLS"
 
1721
                        " priority string (see GnuTLS documentation)")
 
1722
    parser.add_argument("--servicename",
 
1723
                        metavar="NAME", help="Zeroconf service name")
 
1724
    parser.add_argument("--configdir",
 
1725
                        default="/etc/mandos", metavar="DIR",
 
1726
                        help="Directory to search for configuration"
 
1727
                        " files")
 
1728
    parser.add_argument("--no-dbus", action="store_false",
 
1729
                        dest="use_dbus", help="Do not provide D-Bus"
 
1730
                        " system bus interface")
 
1731
    parser.add_argument("--no-ipv6", action="store_false",
 
1732
                        dest="use_ipv6", help="Do not use IPv6")
 
1733
    options = parser.parse_args()
1704
1734
    
1705
1735
    if options.check:
1706
1736
        import doctest
1813
1843
    try:
1814
1844
        os.setgid(gid)
1815
1845
        os.setuid(uid)
1816
 
    except OSError, error:
 
1846
    except OSError as error:
1817
1847
        if error[0] != errno.EPERM:
1818
1848
            raise error
1819
1849
    
1863
1893
        try:
1864
1894
            bus_name = dbus.service.BusName("se.bsnet.fukt.Mandos",
1865
1895
                                            bus, do_not_queue=True)
1866
 
        except dbus.exceptions.NameExistsException, e:
 
1896
        except dbus.exceptions.NameExistsException as e:
1867
1897
            logger.error(unicode(e) + ", disabling D-Bus")
1868
1898
            use_dbus = False
1869
1899
            server_settings["use_dbus"] = False
2019
2049
        # From the Avahi example code
2020
2050
        try:
2021
2051
            service.activate()
2022
 
        except dbus.exceptions.DBusException, error:
 
2052
        except dbus.exceptions.DBusException as error:
2023
2053
            logger.critical("DBusException: %s", error)
2024
2054
            cleanup()
2025
2055
            sys.exit(1)
2032
2062
        
2033
2063
        logger.debug("Starting main loop")
2034
2064
        main_loop.run()
2035
 
    except AvahiError, error:
 
2065
    except AvahiError as error:
2036
2066
        logger.critical("AvahiError: %s", error)
2037
2067
        cleanup()
2038
2068
        sys.exit(1)