e8058322725ba050014777ee2484f7e833ab1e3aLukas Slebodnik#!/usr/bin/python
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek
11496692da75a330de01d5f15b7183d2439efd3cLukas Slebodnikfrom __future__ import print_function
11496692da75a330de01d5f15b7183d2439efd3cLukas Slebodnik
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozekimport sys
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozekfrom optparse import OptionParser
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozekimport pysss
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozekimport SSSDConfig
8d00718b943ab8b326320feb50820f0663031817Stephen Gallagherimport getpass
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek
37ea8e70fa13ff9ba563300fb15de0e5e6185d68Lukas Slebodnik
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozekdef parse_options():
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek parser = OptionParser()
8d00718b943ab8b326320feb50820f0663031817Stephen Gallagher parser.set_description("sss_obfuscate converts a given password into \
8d00718b943ab8b326320feb50820f0663031817Stephen Gallagher human-unreadable format and places it into \
8d00718b943ab8b326320feb50820f0663031817Stephen Gallagher appropriate domain section of the SSSD config \
8d00718b943ab8b326320feb50820f0663031817Stephen Gallagher file. The password can be passed in by stdin, \
8d00718b943ab8b326320feb50820f0663031817Stephen Gallagher specified on the command-line or entered \
8d00718b943ab8b326320feb50820f0663031817Stephen Gallagher interactively")
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek parser.add_option("-s", "--stdin", action="store_true",
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek dest="stdin", default=False,
8d00718b943ab8b326320feb50820f0663031817Stephen Gallagher help="Read the password from stdin.")
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek parser.add_option("-d", "--domain",
c9f6ca2ca7399c301853ff774c20883fef2b2267Stephen Gallagher dest="domain", default=None,
c9f6ca2ca7399c301853ff774c20883fef2b2267Stephen Gallagher help="The domain to use the password in (mandatory)",
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek metavar="DOMNAME")
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek parser.add_option("-f", "--file",
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek dest="filename", default=None,
37ea8e70fa13ff9ba563300fb15de0e5e6185d68Lukas Slebodnik help="Set input file to FILE (default: Use system "
37ea8e70fa13ff9ba563300fb15de0e5e6185d68Lukas Slebodnik "default, usually /etc/sssd/sssd.conf)",
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek metavar="FILE")
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek (options, args) = parser.parse_args()
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek return options, args
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek
37ea8e70fa13ff9ba563300fb15de0e5e6185d68Lukas Slebodnik
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozekdef main():
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek options, args = parse_options()
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek if not options:
11496692da75a330de01d5f15b7183d2439efd3cLukas Slebodnik print("Cannot parse options", file=sys.stderr)
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek return 1
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek
c9f6ca2ca7399c301853ff774c20883fef2b2267Stephen Gallagher if not options.domain:
11496692da75a330de01d5f15b7183d2439efd3cLukas Slebodnik print("No domain specified", file=sys.stderr)
c9f6ca2ca7399c301853ff774c20883fef2b2267Stephen Gallagher return 1
c9f6ca2ca7399c301853ff774c20883fef2b2267Stephen Gallagher
0a0d272844108fe3650a206c39dd4047f10003f2Gowrishankar Rajaiyan if not options.stdin:
675f529e1a0ada1b1a400a59465560ab88a6e24cStephen Gallagher try:
37ea8e70fa13ff9ba563300fb15de0e5e6185d68Lukas Slebodnik pprompt = lambda: (getpass.getpass("Enter password: "),
37ea8e70fa13ff9ba563300fb15de0e5e6185d68Lukas Slebodnik getpass.getpass("Re-enter password: "))
8d00718b943ab8b326320feb50820f0663031817Stephen Gallagher p1, p2 = pprompt()
764bda08267d867a30ceb07d398dc30be1f4b699Stephen Gallagher
37ea8e70fa13ff9ba563300fb15de0e5e6185d68Lukas Slebodnik # Work around bug in Python 2.6
764bda08267d867a30ceb07d398dc30be1f4b699Stephen Gallagher if '\x03' in p1 or '\x03' in p2:
764bda08267d867a30ceb07d398dc30be1f4b699Stephen Gallagher raise KeyboardInterrupt
764bda08267d867a30ceb07d398dc30be1f4b699Stephen Gallagher
675f529e1a0ada1b1a400a59465560ab88a6e24cStephen Gallagher while p1 != p2:
675f529e1a0ada1b1a400a59465560ab88a6e24cStephen Gallagher print('Passwords do not match. Try again')
675f529e1a0ada1b1a400a59465560ab88a6e24cStephen Gallagher p1, p2 = pprompt()
764bda08267d867a30ceb07d398dc30be1f4b699Stephen Gallagher
37ea8e70fa13ff9ba563300fb15de0e5e6185d68Lukas Slebodnik # Work around bug in Python 2.6
764bda08267d867a30ceb07d398dc30be1f4b699Stephen Gallagher if '\x03' in p1 or '\x03' in p2:
764bda08267d867a30ceb07d398dc30be1f4b699Stephen Gallagher raise KeyboardInterrupt
675f529e1a0ada1b1a400a59465560ab88a6e24cStephen Gallagher password = p1
764bda08267d867a30ceb07d398dc30be1f4b699Stephen Gallagher
675f529e1a0ada1b1a400a59465560ab88a6e24cStephen Gallagher except EOFError:
11496692da75a330de01d5f15b7183d2439efd3cLukas Slebodnik print('\nUnexpected end-of-file. Password change aborted',
11496692da75a330de01d5f15b7183d2439efd3cLukas Slebodnik file=sys.stderr)
675f529e1a0ada1b1a400a59465560ab88a6e24cStephen Gallagher return 1
764bda08267d867a30ceb07d398dc30be1f4b699Stephen Gallagher except KeyboardInterrupt:
764bda08267d867a30ceb07d398dc30be1f4b699Stephen Gallagher return 1
8d00718b943ab8b326320feb50820f0663031817Stephen Gallagher
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek else:
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek try:
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek password = sys.stdin.read()
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek except KeyboardInterrupt:
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek return 1
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek # Obfuscate the password
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek obfobj = pysss.password()
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek obfpwd = obfobj.encrypt(password, obfobj.AES_256)
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek # Save the obfuscated password into the domain
5daa8ae758349c0077fb5f664579809aa0ab4f78Stephen Gallagher try:
5daa8ae758349c0077fb5f664579809aa0ab4f78Stephen Gallagher sssdconfig = SSSDConfig.SSSDConfig()
5daa8ae758349c0077fb5f664579809aa0ab4f78Stephen Gallagher except IOError:
11496692da75a330de01d5f15b7183d2439efd3cLukas Slebodnik print("Cannot read internal configuration files.")
5daa8ae758349c0077fb5f664579809aa0ab4f78Stephen Gallagher return 1
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek try:
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek sssdconfig.import_config(options.filename)
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek except IOError:
11496692da75a330de01d5f15b7183d2439efd3cLukas Slebodnik print("Permissions error reading config file")
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek return 1
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek try:
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek domain = sssdconfig.get_domain(options.domain)
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek except SSSDConfig.NoDomainError:
11496692da75a330de01d5f15b7183d2439efd3cLukas Slebodnik print("No such domain %s" % options.domain)
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek return 1
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek try:
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek domain.set_option('ldap_default_authtok_type', 'obfuscated_password')
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek domain.set_option('ldap_default_authtok', obfpwd)
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek except SSSDConfig.NoOptionError:
11496692da75a330de01d5f15b7183d2439efd3cLukas Slebodnik print("The domain %s does not seem to support the required options"
11496692da75a330de01d5f15b7183d2439efd3cLukas Slebodnik % options.domain)
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek return 1
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek sssdconfig.save_domain(domain)
5daa8ae758349c0077fb5f664579809aa0ab4f78Stephen Gallagher try:
5daa8ae758349c0077fb5f664579809aa0ab4f78Stephen Gallagher sssdconfig.write()
5daa8ae758349c0077fb5f664579809aa0ab4f78Stephen Gallagher except IOError:
5daa8ae758349c0077fb5f664579809aa0ab4f78Stephen Gallagher # File could not be written
11496692da75a330de01d5f15b7183d2439efd3cLukas Slebodnik print("Could not write to config file. Check that you have the "
11496692da75a330de01d5f15b7183d2439efd3cLukas Slebodnik "appropriate permissions to edit this file.", file=sys.stderr)
5daa8ae758349c0077fb5f664579809aa0ab4f78Stephen Gallagher return 1
5daa8ae758349c0077fb5f664579809aa0ab4f78Stephen Gallagher
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek return 0
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozekif __name__ == "__main__":
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek ret = main()
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek sys.exit(ret)