cred_unix.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. # -*- test-case-name: twisted.test.test_strcred -*-
  2. #
  3. # Copyright (c) Twisted Matrix Laboratories.
  4. # See LICENSE for details.
  5. """
  6. Cred plugin for UNIX user accounts.
  7. """
  8. from __future__ import absolute_import, division
  9. from zope.interface import implementer
  10. from twisted import plugin
  11. from twisted.cred.strcred import ICheckerFactory
  12. from twisted.cred.checkers import ICredentialsChecker
  13. from twisted.cred.credentials import IUsernamePassword
  14. from twisted.cred.error import UnauthorizedLogin
  15. from twisted.internet import defer
  16. def verifyCryptedPassword(crypted, pw):
  17. if crypted[0] == '$': # md5_crypt encrypted
  18. salt = '$1$' + crypted.split('$')[2]
  19. else:
  20. salt = crypted[:2]
  21. try:
  22. import crypt
  23. except ImportError:
  24. crypt = None
  25. if crypt is None:
  26. raise NotImplementedError("cred_unix not supported on this platform")
  27. return crypt.crypt(pw, salt) == crypted
  28. @implementer(ICredentialsChecker)
  29. class UNIXChecker(object):
  30. """
  31. A credentials checker for a UNIX server. This will check that
  32. an authenticating username/password is a valid user on the system.
  33. Does not work on Windows.
  34. Right now this supports Python's pwd and spwd modules, if they are
  35. installed. It does not support PAM.
  36. """
  37. credentialInterfaces = (IUsernamePassword,)
  38. def checkPwd(self, pwd, username, password):
  39. try:
  40. cryptedPass = pwd.getpwnam(username)[1]
  41. except KeyError:
  42. return defer.fail(UnauthorizedLogin())
  43. else:
  44. if cryptedPass in ('*', 'x'):
  45. # Allow checkSpwd to take over
  46. return None
  47. elif verifyCryptedPassword(cryptedPass, password):
  48. return defer.succeed(username)
  49. def checkSpwd(self, spwd, username, password):
  50. try:
  51. cryptedPass = spwd.getspnam(username)[1]
  52. except KeyError:
  53. return defer.fail(UnauthorizedLogin())
  54. else:
  55. if verifyCryptedPassword(cryptedPass, password):
  56. return defer.succeed(username)
  57. def requestAvatarId(self, credentials):
  58. username, password = credentials.username, credentials.password
  59. try:
  60. import pwd
  61. except ImportError:
  62. pwd = None
  63. if pwd is not None:
  64. checked = self.checkPwd(pwd, username, password)
  65. if checked is not None:
  66. return checked
  67. try:
  68. import spwd
  69. except ImportError:
  70. spwd = None
  71. if spwd is not None:
  72. checked = self.checkSpwd(spwd, username, password)
  73. if checked is not None:
  74. return checked
  75. # TODO: check_pam?
  76. # TODO: check_shadow?
  77. return defer.fail(UnauthorizedLogin())
  78. unixCheckerFactoryHelp = """
  79. This checker will attempt to use every resource available to
  80. authenticate against the list of users on the local UNIX system.
  81. (This does not support Windows servers for very obvious reasons.)
  82. Right now, this includes support for:
  83. * Python's pwd module (which checks /etc/passwd)
  84. * Python's spwd module (which checks /etc/shadow)
  85. Future versions may include support for PAM authentication.
  86. """
  87. @implementer(ICheckerFactory, plugin.IPlugin)
  88. class UNIXCheckerFactory(object):
  89. """
  90. A factory for L{UNIXChecker}.
  91. """
  92. authType = 'unix'
  93. authHelp = unixCheckerFactoryHelp
  94. argStringFormat = 'No argstring required.'
  95. credentialInterfaces = UNIXChecker.credentialInterfaces
  96. def generateChecker(self, argstring):
  97. """
  98. This checker factory ignores the argument string. Everything
  99. needed to generate a user database is pulled out of the local
  100. UNIX environment.
  101. """
  102. return UNIXChecker()
  103. theUnixCheckerFactory = UNIXCheckerFactory()