Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/python
- #
- #
- """Demotes a Mobile Account to a standalone account."""
- import os
- import shutil
- import subprocess
- import sys
- import plistlib
- import xml
- class ConvertMobileError(Exception):
- """Module specific Exception."""
- pass
- def _ConvertPlistToXML(plist):
- """Converts a plist to the xml1 format.
- Args:
- plist: the property list to be converted.
- Raises:
- ConvertMobileError: plist does not exist.
- ConvertMobileError: Error converting.
- """
- if not os.path.isfile(plist):
- raise ConvertMobileError("%s does not exist" % plist)
- command = ["/usr/bin/plutil", "-convert", "xml1", plist]
- task = subprocess.Popen(command, stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
- (unused_stdout, stderr) = task.communicate()
- if task.returncode:
- raise ConvertMobileError("Error converting %s : %s" % (plist, stderr))
- def _ReadPlist(plist):
- """Reads a plist, converting to xml1 if necessary.
- Args:
- plist: the property list to be read/converted.
- Raises:
- ConvertMobileError: plist is not a file
- Returns:
- plist_dict: a dictionary object with the plist contents.
- """
- if not os.path.isfile(plist):
- raise ConvertMobileError("%s is not a file" % plist)
- try:
- plist_dict = plistlib.readPlist(plist)
- except xml.parsers.expat.ExpatError:
- _ConvertPlistToXML(plist)
- plist_dict = plistlib.readPlist(plist)
- return plist_dict
- def _VerifyMacOSXVersion():
- """Checks the Mac OS X version is 10.5.
- Returns:
- boolean: whether this is OS X 10.5
- """
- sysvers_plist = "/System/Library/CoreServices/SystemVersion.plist"
- plist = _ReadPlist(sysvers_plist)
- if plist["ProductVersion"].startswith("10.5"):
- return True
- else:
- return False
- def _CheckUserIsLocal(user):
- """Checks whether a given account exists in the local domain.
- Args:
- user: the username to check
- Returns:
- boolean: whether an account exists for that user.
- """
- command = ["/usr/bin/dscl", ".", "-read", "/Users/%s" % user, "UniqueID"]
- if subprocess.call(command, stdout=subprocess.PIPE):
- return False
- else:
- return True
- def _GenerateUUID():
- """generates a uuid.
- Returns:
- uuid: the uuid
- Raises:
- ConvertMobileError: Unable to generate uuid.
- """
- task = subprocess.Popen(["/usr/bin/uuidgen"], stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
- (stdout, stderr) = task.communicate()
- if task.returncode:
- raise ConvertMobileError("Cannot generate UUID: %s" % stderr)
- return str(stdout).strip()
- def _EnsureAccountIsNotMobile(user):
- """Ensures a given user account is not a Mobile Account.
- Strips attributes if necessary.
- Args:
- user: the short name of the user account.
- """
- user_plist = "/var/db/dslocal/nodes/Default/users/%s.plist" % user
- account = _ReadPlist(user_plist)
- if "account_instance" in account:
- uuid = account["account_instance"][0]
- elif "generateduid" in account:
- uuid = account["generateduid"][0]
- else:
- uuid = _GenerateUUID()
- mobile_attrs = ["account_instance", "cached_groups", "copy_timestamp",
- "original_home", "original_node_name", "original_passwd",
- "original_realname", "original_shell",
- "preserved_attributes", "mcx_flags", "mcx_settings"]
- for attr in mobile_attrs:
- if attr in account:
- del account[attr]
- account["gid"] = [str(20)] # 'staff' group.
- account["generateduid"] = [uuid]
- new_auth_authority = []
- new_auth_authority.append(";ShadowHash;")
- for authority in account["authentication_authority"]:
- if authority.startswith(";Kerberosv5;"): # keep their LKDC authority
- new_auth_authority.append(authority)
- account["authentication_authority"] = new_auth_authority
- # write out new account to the user plist.
- plistlib.writePlist(account, user_plist)
- # move the shadow hash file to the proper location
- old_hash = "/var/db/shadow/hash/%s" % user
- new_hash = "/var/db/shadow/hash/%s" % uuid
- if not os.path.isfile(old_hash) and not os.path.isfile(new_hash):
- print "No password hashes at: %s or %s" % (old_hash, new_hash)
- print "You should run the following command now to set a password:"
- print ""
- print "dscl . -passwd /Users/%s" % user
- print ""
- if os.path.isfile(old_hash) and not os.path.isfile(new_hash):
- shutil.move(old_hash, new_hash)
- def _RestartDirectoryServices():
- """Restarts DirectoryServices process."""
- command = ["/usr/bin/killall", "-TERM", "DirectoryService"]
- if subprocess.call(command, stdout=subprocess.PIPE):
- raise ConvertMobileError("Problem killing DirectoryService.")
- def main():
- try:
- user = sys.argv[1]
- except IndexError:
- raise ConvertMobileError("You must pass the username as the only arg.")
- if os.getuid() is not 0:
- raise ConvertMobileError("This script must be run as root.")
- if not _VerifyMacOSXVersion():
- raise ConvertMobileError("This script must be run on Mac OS X 10.5.")
- if not _CheckUserIsLocal(user):
- raise ConvertMobileError("User: %s does not exist locally." % user)
- _EnsureAccountIsNotMobile(user)
- _RestartDirectoryServices()
- if __name__ == "__main__":
- main()
Add Comment
Please, Sign In to add comment