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.

181 lines
5.4 KiB

  1. #!/usr/bin/env python2.4
  2. #
  3. # Copyright (c) 2003-2006 Andrea Luzzardi <scox@sig11.org>
  4. #
  5. # This file is part of the pam_usb project. pam_usb is free software;
  6. # you can redistribute it and/or modify it under the terms of the GNU General
  7. # Public License version 2, as published by the Free Software Foundation.
  8. #
  9. # pam_usb is distributed in the hope that it will be useful, but WITHOUT ANY
  10. # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  11. # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  12. # details.
  13. #
  14. # You should have received a copy of the GNU General Public License along with
  15. # this program; if not, write to the Free Software Foundation, Inc., 59 Temple
  16. # Place, Suite 330, Boston, MA 02111-1307 USA
  17. import os
  18. import sys
  19. import pwd
  20. import getopt
  21. import gobject
  22. import dbus
  23. if getattr(dbus, 'version', (0,0,0)) >= (0,41,0):
  24. import dbus.glib
  25. try:
  26. import cElementTree as et
  27. except ImportError:
  28. import elementtree.ElementTree as et
  29. class HotPlugDevice:
  30. def __init__(self, serial):
  31. self.__udi = None
  32. self.__serial = serial
  33. self.__callbacks = []
  34. self.__bus = dbus.SystemBus()
  35. self.__running = False
  36. def run(self):
  37. self.__scanDevices()
  38. self.__registerSignals()
  39. self.__running = True
  40. gobject.MainLoop().run()
  41. print 'signals registered'
  42. def addCallback(self, callback):
  43. self.__callbacks.append(callback)
  44. def __scanDevices(self):
  45. halService = self.__bus.get_object('org.freedesktop.Hal',
  46. '/org/freedesktop/Hal/Manager')
  47. halManager = dbus.Interface(halService, 'org.freedesktop.Hal.Manager')
  48. for udi in halManager.FindDeviceStringMatch('info.bus', 'usb_device'):
  49. self.__deviceAdded(udi)
  50. def __registerSignals(self):
  51. for signal, callback in (('DeviceAdded', self.__deviceAdded),
  52. ('DeviceRemoved', self.__deviceRemoved)):
  53. self.__bus.add_signal_receiver(callback,
  54. signal,
  55. 'org.freedesktop.Hal.Manager',
  56. 'org.freedesktop.Hal',
  57. '/org/freedesktop/Hal/Manager')
  58. def __deviceAdded(self, udi):
  59. if self.__udi is not None:
  60. return
  61. deviceObj = self.__bus.get_object('org.freedesktop.Hal',
  62. udi)
  63. deviceProperties = deviceObj.GetAllProperties(
  64. dbus_interface = 'org.freedesktop.Hal.Device')
  65. if not deviceProperties.has_key('usb_device.serial'):
  66. return
  67. if deviceProperties['usb_device.serial'] != self.__serial:
  68. return
  69. self.__udi = udi
  70. print 'Device %s added' % udi
  71. if self.__running:
  72. [ cb('added') for cb in self.__callbacks ]
  73. def __deviceRemoved(self, udi):
  74. if self.__udi is None:
  75. return
  76. if self.__udi != udi:
  77. return
  78. self.__udi = None
  79. print 'Device %s removed' % udi
  80. if self.__running:
  81. [ cb('removed') for cb in self.__callbacks ]
  82. def usage():
  83. print 'Usage: %s [--config file] [--daemon] [--path pusb_check_path]' \
  84. % sys.argv[0]
  85. sys.exit(1)
  86. import getopt
  87. try:
  88. opts, args = getopt.getopt(sys.argv[1:], "hc:dp:",
  89. ["help", "config=", "daemon", "path="])
  90. except getopt.GetoptError:
  91. usage()
  92. options = {'configFile' : '/etc/pam_usb/pusb.conf',
  93. 'daemon' : False,
  94. 'path' : '/usr/bin/pusb_check'}
  95. if len(args) != 0:
  96. usage()
  97. for o, a in opts:
  98. if o in ('-h', '--help'):
  99. usage()
  100. if o in ('-c', '--config'):
  101. options['configFile'] = a
  102. if o in ('-d', '--daemon'):
  103. options['daemon'] = True
  104. if o in ('-p', '--path'):
  105. options['path'] = a
  106. if not os.path.exists(options['path']):
  107. print '%s not found.' % options['path']
  108. print "You might specify manually pusb_check's location using --path."
  109. usage()
  110. username = pwd.getpwuid(os.getuid())[0]
  111. print 'Running pusb_hotplug for user %s' % username
  112. doc = et.parse(options['configFile'])
  113. users = doc.findall('users/user')
  114. for user in users:
  115. if user.get('id') == username:
  116. break
  117. else:
  118. print 'User %s not found' % username
  119. events = {
  120. 'lock' : [],
  121. 'unlock' : []
  122. }
  123. for hotplug in user.findall('hotplug'):
  124. events[hotplug.get('event')].append(hotplug.text)
  125. deviceName = user.find('device').text
  126. devices = doc.findall("devices/device")
  127. for device in devices:
  128. if device.get('id') == deviceName:
  129. break
  130. else:
  131. print 'Device %s not found' % deviceName
  132. serial = device.find('serial').text
  133. def authChangeCallback(event):
  134. print 'User %s is now %s' % (username, event)
  135. cmdLine = "%s -q -c %s -u %s -s pusb_hotplug -a" % (options['path'],
  136. options['configFile'],
  137. username)
  138. print 'Executing %s' % cmdLine
  139. if not os.system(cmdLine):
  140. run = events['unlock']
  141. else:
  142. run = events['lock']
  143. [os.system(e) for e in run]
  144. hpDev = HotPlugDevice(serial)
  145. hpDev.addCallback(authChangeCallback)
  146. if options['daemon'] and os.fork():
  147. sys.exit(0)
  148. try:
  149. hpDev.run()
  150. except KeyboardInterrupt:
  151. print 'Exiting...'