#!/usr/bin/python -tt # seth vidal # Copyright 2011, Red Hat, Inc ## ## This software may be freely redistributed under the terms of the GNU ## general public license. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. import sys import func.overlord.client from func.overlord.scripts import errorprint from optparse import OptionParser from func.utils import is_error import crypt import getpass import tempfile import os import time def parse_args(args): parser = OptionParser(version = "1.0") parser.set_usage("func-change-password username") parser.add_option('--host', default=[], action='append', help="hosts to act on, defaults to ALL") parser.add_option('--timeout', default=300, type='int', help='set the wait timeout for func commands') parser.add_option('--forks', default=40, type='int', help='set the number of forks to start up') parser.add_option('--grep-options', default='-n', dest='grep_options', help='set options to pass to grep "-r -i" for example') parser.add_option('--hosts-from-file', default=None, dest="hostfile", help="read list of hosts from this file, if '-' read from stdin") (opts, args) = parser.parse_args(args) if opts.hostfile: hosts = [] if opts.hostfile == '-': hosts = sys.stdin.readlines() else: hosts = open(opts.hostfile, 'r').readlines() for hn in hosts: hn = hn.strip() if hn.startswith('#'): continue hn = hn.replace('\n', '') opts.host.append(hn) return opts, args, parser def main(): opts, args, parser = parse_args(sys.argv[1:]) if len(args) < 1: print parser.format_help() sys.exit(1) hosts ='*' if opts.host: hosts = ';'.join(opts.host) username = args[0] print "Changing password on hosts for %s" % username password = 'new' password_re = 'new1' while password != password_re: # take the password for the user password = getpass.getpass() password_re = getpass.getpass("Confirm Password: ") if password != password_re: print "Passwords do not match!" print "Trying again" if password == '' or password_re == '': print "Empty, aborting" sys.exit(1) # generate salt salt = '$6$' + ''.join(map(lambda x:'./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'[ord(x)%64], os.urandom(16))) # generate crypt crypted = crypt.crypt(password, salt) # write to tempfile (pw_fd, pw_tmp) = tempfile.mkstemp(prefix='fcp', text=True) pw_fo = os.fdopen(pw_fd, 'w') pw_str = '%s:%s\n' % (username, crypted) pw_fo.write(pw_str) pw_fo.flush() pw_fo.close() # send to hosts to specific location fc = func.overlord.client.Client(hosts, timeout=opts.timeout, nforks=opts.forks) source = pw_tmp dest = "/root/fcp-%s" % time.strftime("%s") print 'Sending changes to hosts' results = fc.local.copyfile.send(source, dest) # check results # copyfile fucking sucks - this needs something USEFUL # any failures - take those out of the hosts and make a new fc connection # run chpasswd on the hosts sending that file to it print "Changing passwords" results = fc.command.run('cat %s | /usr/sbin/chpasswd -e' % dest) # check results # changed_on = [] errors = {} for (hn, output) in results.items(): if is_error(output) or output[0] == 127: msg = 'Error: ' for item in output[1:3]: if type(item) == type(''): msg += ' %s' % item msg += '\n' errors[hn] = msg continue if output[0] != 0: msg = 'Error: %s %s\n' % (output[0], output[1]) errors[hn] = msg continue changed_on.append(hn) # clean up # rm the file from the hosts and rm it locally print "Cleaning up" os.unlink(pw_tmp) results = fc.command.run('/bin/rm -f %s' % dest) for (hn, output) in results.items(): if is_error(output) or output[0] == 127: msg = 'Error: ' for item in output[1:3]: if type(item) == type(''): msg += ' %s' % item msg += '\n' if msg == errors[hn]: continue else: errors[hn] += msg continue if output[0] != 0: msg = 'Error: %s %s\n' % (output[0], output[1]) if msg == errors[hn]: continue else: errors[hn] += msg continue print "Password for %s changed on:" % username for hn in sorted(changed_on): print ' %s' % hn print "\n\nErrors from: " for hn in errors: print ' %s' % hn print ' %s' % errors[hn] if __name__ == "__main__": try: main() except KeyboardInterrupt, e: print "Exiting on user interrupt" sys.exit(1)