Hardware authentication for Linux using ordinary USB Flash Drives.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

166 lines
4.6 KiB

  1. #!/usr/bin/env python2.4
  2. import os
  3. import sys
  4. import pwd
  5. import getopt
  6. import gobject
  7. import dbus
  8. if getattr(dbus, 'version', (0,0,0)) >= (0,41,0):
  9. import dbus.glib
  10. try:
  11. import cElementTree as et
  12. except ImportError:
  13. import elementtree.ElementTree as et
  14. class HotPlugDevice:
  15. def __init__(self, serial):
  16. self.__udi = None
  17. self.__serial = serial
  18. self.__callbacks = []
  19. self.__bus = dbus.SystemBus()
  20. self.__running = False
  21. def run(self):
  22. self.__scanDevices()
  23. self.__registerSignals()
  24. self.__running = True
  25. gobject.MainLoop().run()
  26. print 'signals registered'
  27. def addCallback(self, callback):
  28. self.__callbacks.append(callback)
  29. def __scanDevices(self):
  30. halService = self.__bus.get_object('org.freedesktop.Hal',
  31. '/org/freedesktop/Hal/Manager')
  32. halManager = dbus.Interface(halService, 'org.freedesktop.Hal.Manager')
  33. for udi in halManager.FindDeviceStringMatch('info.bus', 'usb_device'):
  34. self.__deviceAdded(udi)
  35. def __registerSignals(self):
  36. for signal, callback in (('DeviceAdded', self.__deviceAdded),
  37. ('DeviceRemoved', self.__deviceRemoved)):
  38. self.__bus.add_signal_receiver(callback,
  39. signal,
  40. 'org.freedesktop.Hal.Manager',
  41. 'org.freedesktop.Hal',
  42. '/org/freedesktop/Hal/Manager')
  43. def __deviceAdded(self, udi):
  44. if self.__udi is not None:
  45. return
  46. deviceObj = self.__bus.get_object('org.freedesktop.Hal',
  47. udi)
  48. deviceProperties = deviceObj.GetAllProperties(
  49. dbus_interface = 'org.freedesktop.Hal.Device')
  50. if not deviceProperties.has_key('usb_device.serial'):
  51. return
  52. if deviceProperties['usb_device.serial'] != self.__serial:
  53. return
  54. self.__udi = udi
  55. print 'Device %s added' % udi
  56. if self.__running:
  57. [ cb('added') for cb in self.__callbacks ]
  58. def __deviceRemoved(self, udi):
  59. if self.__udi is None:
  60. return
  61. if self.__udi != udi:
  62. return
  63. self.__udi = None
  64. print 'Device %s removed' % udi
  65. if self.__running:
  66. [ cb('removed') for cb in self.__callbacks ]
  67. def usage():
  68. print 'Usage: %s [--config file] [--daemon] [--path pusb_check_path]' \
  69. % sys.argv[0]
  70. sys.exit(1)
  71. import getopt
  72. try:
  73. opts, args = getopt.getopt(sys.argv[1:], "hc:dp:",
  74. ["help", "config=", "daemon", "path="])
  75. except getopt.GetoptError:
  76. usage()
  77. options = {'configFile' : '/etc/pam_usb/pusb.conf',
  78. 'daemon' : False,
  79. 'path' : '/usr/bin/pusb_check'}
  80. if len(args) != 0:
  81. usage()
  82. for o, a in opts:
  83. if o in ('-h', '--help'):
  84. usage()
  85. if o in ('-c', '--config'):
  86. options['configFile'] = a
  87. if o in ('-d', '--daemon'):
  88. options['daemon'] = True
  89. if o in ('-p', '--path'):
  90. options['path'] = a
  91. if not os.path.exists(options['path']):
  92. print '%s not found.' % options['path']
  93. print "You might specify manually pusb_check's location using --path."
  94. usage()
  95. username = pwd.getpwuid(os.getuid())[0]
  96. print 'Running pusb_hotplug for user %s' % username
  97. doc = et.parse(options['configFile'])
  98. users = doc.findall('users/user')
  99. for user in users:
  100. if user.get('id') == username:
  101. break
  102. else:
  103. print 'User %s not found' % username
  104. events = {
  105. 'lock' : [],
  106. 'unlock' : []
  107. }
  108. for hotplug in user.findall('hotplug'):
  109. events[hotplug.get('event')].append(hotplug.text)
  110. deviceName = user.find('device').text
  111. devices = doc.findall("devices/device")
  112. for device in devices:
  113. if device.get('id') == deviceName:
  114. break
  115. else:
  116. print 'Device %s not found' % deviceName
  117. serial = device.find('serial').text
  118. def authChangeCallback(event):
  119. print 'User %s is now %s' % (username, event)
  120. cmdLine = "%s -q -c %s -u %s -s pusb_hotplug -a" % (options['path'],
  121. options['configFile'],
  122. username)
  123. print 'Executing %s' % cmdLine
  124. if not os.system(cmdLine):
  125. run = events['unlock']
  126. else:
  127. run = events['lock']
  128. [os.system(e) for e in run]
  129. hpDev = HotPlugDevice(serial)
  130. hpDev.addCallback(authChangeCallback)
  131. if options['daemon'] and os.fork():
  132. sys.exit(0)
  133. try:
  134. hpDev.run()
  135. except KeyboardInterrupt:
  136. print 'Exiting...'