Providers/Scripts/2.4x-2.5x/Scripts/nxUser.py (426 lines of code) (raw):

#!/usr/bin/env python # =================================== # Copyright (c) Microsoft Corporation. All rights reserved. # See license.txt for license information. # =================================== import os import sys import datetime import imp import copy import fnmatch protocol = imp.load_source('protocol', '../protocol.py') nxDSCLog = imp.load_source('nxDSCLog', '../nxDSCLog.py') helperlib = imp.load_source('helperlib', '../helperlib.py') LG = nxDSCLog.DSCLog # [ClassVersion("1.0.0"), FriendlyName("nxUser"),SupportsInventory()] # class MSFT_nxUserResource : OMI_BaseResource # { # [Key, InventoryFilter] string UserName; # [write,ValueMap{"Present", "Absent"},Values{"Present", "Absent"}] string Ensure; # [write, InventoryFilter] string FullName; # [write, InventoryFilter] string Description; # [write] string Password; # [write] boolean Disabled; # [write] boolean PasswordChangeRequired; # [write] string HomeDirectory; # [write] string GroupID; # [read] string UserID; # }; global show_mof show_mof = False def init_vars(UserName, Ensure, FullName, Description, Password, Disabled, PasswordChangeRequired, HomeDirectory, GroupID): if UserName is not None: UserName = UserName.encode('ascii', 'ignore') else: UserName = '' if Ensure is not None and Ensure != '': Ensure = Ensure.encode('ascii', 'ignore').lower() else: Ensure = 'present' if FullName is not None: FullName = FullName.encode('ascii', 'ignore') else: FullName = '' if Description is not None: Description = Description.encode('ascii', 'ignore') else: Description = '' if Password is not None: Password = Password.encode('ascii', 'ignore') else: Password = '' if Disabled is None: Disabled = False Disabled = ( Disabled == True ) # this arrives as a 0 or 1 if PasswordChangeRequired is None: PasswordChangeRequired = False PasswordChangeRequired = ( PasswordChangeRequired == True ) # this arrives as a 0 or 1 if HomeDirectory is not None: HomeDirectory = HomeDirectory.encode('ascii', 'ignore') else: HomeDirectory = '' if GroupID is not None: GroupID = GroupID.encode('ascii', 'ignore') else: GroupID = '' return UserName, Ensure, FullName, Description, Password, Disabled, PasswordChangeRequired, HomeDirectory, GroupID def Set_Marshall(UserName, Ensure, FullName, Description, Password, Disabled, PasswordChangeRequired, HomeDirectory, GroupID): if helperlib.CONFIG_SYSCONFDIR_DSC == "omsconfig": return [-1] (UserName, Ensure, FullName, Description, Password, Disabled, PasswordChangeRequired, HomeDirectory, GroupID) = \ init_vars(UserName, Ensure, FullName, Description, Password, Disabled, PasswordChangeRequired, HomeDirectory, GroupID) retval = Set(UserName, Ensure, FullName, Description, Password, Disabled, PasswordChangeRequired, HomeDirectory, GroupID) return retval def Test_Marshall(UserName, Ensure, FullName, Description, Password, Disabled, PasswordChangeRequired, HomeDirectory, GroupID): if helperlib.CONFIG_SYSCONFDIR_DSC == "omsconfig": return [-1] (UserName, Ensure, FullName, Description, Password, Disabled, PasswordChangeRequired, HomeDirectory, GroupID) = \ init_vars(UserName, Ensure, FullName, Description, Password, Disabled, PasswordChangeRequired, HomeDirectory, GroupID) retval = Test(UserName, Ensure, FullName, Description, Password, Disabled, PasswordChangeRequired, HomeDirectory, GroupID) return retval def Get_Marshall(UserName, Ensure, FullName, Description, Password, Disabled, PasswordChangeRequired, HomeDirectory, GroupID): if helperlib.CONFIG_SYSCONFDIR_DSC == "omsconfig": return [-1] arg_names = list(locals().keys()) (UserName, Ensure, FullName, Description, Password, Disabled, PasswordChangeRequired, HomeDirectory, GroupID) = \ init_vars(UserName, Ensure, FullName, Description, Password, Disabled, PasswordChangeRequired, HomeDirectory, GroupID) retval = 0 (retval, UserName, Ensure, FullName, Description, Password, Disabled, PasswordChangeRequired, HomeDirectory, GroupID, UserID) = Get( UserName, Ensure, FullName, Description, Password, Disabled, PasswordChangeRequired, HomeDirectory, GroupID) UserName = protocol.MI_String(UserName) Ensure = protocol.MI_String(Ensure) FullName = protocol.MI_String(FullName) PasswordChangeRequired = protocol.MI_Boolean(PasswordChangeRequired) Disabled = protocol.MI_Boolean(Disabled) Description = protocol.MI_String(Description) Password = protocol.MI_String(Password) HomeDirectory = protocol.MI_String(HomeDirectory) GroupID = protocol.MI_String(GroupID) UserID = protocol.MI_String(UserID) arg_names.append('UserID') retd = {} ld = locals() for k in arg_names: retd[k] = ld[k] return retval, retd def Inventory_Marshall(UserName, Ensure, FullName, Description, Password, Disabled, PasswordChangeRequired, HomeDirectory, GroupID): (UserName, Ensure, FullName, Description, Password, Disabled, PasswordChangeRequired, HomeDirectory, GroupID) = \ init_vars(UserName, Ensure, FullName, Description, Password, Disabled, PasswordChangeRequired, HomeDirectory, GroupID) (retval, Inventory) = GetInventory( UserName, Ensure, FullName, Description, Password, Disabled, PasswordChangeRequired, HomeDirectory, GroupID) for d in Inventory: d['UserName'] = protocol.MI_String(d['UserName']) d['Ensure'] = protocol.MI_String('Present') d['FullName'] = protocol.MI_String(d['FullName']) d['PasswordChangeRequired'] = protocol.MI_Boolean(d['PasswordChangeRequired']) d['Disabled'] = protocol.MI_Boolean(d['Disabled']) d['Description'] = protocol.MI_String(d['Description']) d['Password'] = protocol.MI_String(d['Password']) d['HomeDirectory'] = protocol.MI_String(d['HomeDirectory']) d['GroupID'] = protocol.MI_String(d['GroupID']) d['UserID'] = protocol.MI_String(d['UserID']) d = protocol.MI_Instance(d) Inventory = protocol.MI_InstanceA(Inventory) retd = {} retd["__Inventory"] = Inventory return retval, retd ############################################################ # Begin user defined DSC functions ############################################################ def SetShowMof(a): global show_mof show_mof = a def ShowMof(op, UserName, Ensure, FullName, Description, Password, Disabled, PasswordChangeRequired, HomeDirectory, GroupID): if not show_mof: return mof = '' mof += op + ' nxUser MyUser \n' mof += '{\n' mof += ' UserName = "' + UserName + '"\n' mof += ' Ensure = "' + Ensure + '"\n' mof += ' FullName = "' + FullName + '"\n' mof += ' Description = "' + Description + '"\n' mof += ' Password = "' + Password + '"\n' mof += ' Disabled = ' + str(Disabled) + '\n' mof += ' PasswordChangeRequired = ' + str(PasswordChangeRequired) + '\n' mof += ' HomeDirectory = "' + HomeDirectory + '"\n' mof += ' GroupID = "' + str(GroupID) + '"\n' mof += '}\n' f = open('./test_mofs.log', 'a') Print(mof, file=f) LG().Log('INFO', mof) f.close() def Print(s, file=sys.stdout): file.write(s + '\n') def opened_w_error(filename, mode="r"): """ This context ensures the file is closed. """ try: f = open(filename, mode=mode) except IOError, err: return None, err return f, None userdel_path = "/usr/sbin/userdel" useradd_path = "/usr/sbin/useradd" usermod_path = "/usr/sbin/usermod" chage_path = "/usr/bin/chage" def ReadPasswd(filename): f, error = opened_w_error(filename, 'rb') if error: Print("Exception opening file " + filename + " Error: " + str(error), file=sys.stderr) LG().Log('ERROR', "Exception opening file " + filename + " Error: " + str(error)) return None else: lines = f.read().split("\n") f.close() entries = dict() for line in lines: tokens = line.split(":") if len(tokens) > 1: entries[tokens[0]] = tokens[1:] return entries def PasswordExpired(shadow_entry): # No entries for the "last" field means Password is Expired. if shadow_entry[1] == "": return True # Passwords must be changed if their "last" day is 0 if shadow_entry[1] == "0": return True # "99999" means "never expire" if shadow_entry[3] == "99999" or shadow_entry[3] == "" : return False day_0 = datetime.datetime.utcfromtimestamp(0) day_now = datetime.datetime.today() days_since_day_0 = (day_now - day_0).days days_since_last_password_change = days_since_day_0 - int(shadow_entry[1]) number_of_days_password_is_valid_for = int(shadow_entry[3]) if days_since_last_password_change > number_of_days_password_is_valid_for: return True return False def Set(UserName, Ensure, FullName, Description, Password, Disabled, PasswordChangeRequired, HomeDirectory, GroupID): ShowMof('SET', UserName, Ensure, FullName, Description, Password, Disabled, PasswordChangeRequired, HomeDirectory, GroupID) passwd_entries = None shadow_entries = None passwd_entries = ReadPasswd("/etc/passwd") if passwd_entries is None: return [-1] shadow_entries = ReadPasswd("/etc/shadow") if shadow_entries is None: return [-1] old_passwd_entries = passwd_entries usermod_string = "" usermodonly_string = "" if Ensure == "absent": exit_code = os.system(userdel_path + " " + UserName) else: usermod_string = "" if FullName or Description: usermod_string += " -c \"" if FullName: usermod_string += FullName if Description: usermod_string += "," + Description usermod_string += "\"" if HomeDirectory: usermod_string += " -d \"" + HomeDirectory + "\" -m " if GroupID: usermod_string += " -g " + GroupID if UserName not in passwd_entries: exit_code = os.system( useradd_path + " " + usermod_string + " " + UserName) if exit_code is not 0: return [exit_code] if len(usermodonly_string) > 0: exit_code = os.system( usermod_path + " " + usermodonly_string + " " + UserName) else: Print(usermod_string, file=sys.stderr) LG().Log('INFO', usermod_string) if len(usermodonly_string + usermod_string) > 0: exit_code = os.system( usermod_path + " " + usermodonly_string + usermod_string + " " + UserName) disabled_user_string = "" usermod_string = "" if Disabled is True: disabled_user_string = "!" if len(Password) > 0: usermod_string += " -p \"" + disabled_user_string + \ Password.replace("$", "\$") + "\"" elif Disabled is True: usermodonly_string += " -L" elif Disabled is False: passwd_entries = ReadPasswd("/etc/passwd") if passwd_entries is None: return [-1] shadow_entries = ReadPasswd("/etc/shadow") if shadow_entries is None: return [-1] if UserName in shadow_entries: cur_pass = shadow_entries[UserName][0] if cur_pass == "!!": Print("Unable to unlock user: " + UserName + ". Password is not set.", file=sys.stderr) LG().Log('ERROR', "Unable to unlock user: " + UserName + ". Password is not set.") return [-1] elif cur_pass[0] == '!': if len(cur_pass) > 1: usermodonly_string += " -U" else: Print("Unable to unlock user: " + UserName + ". Doing so would result in a passwordless account.", file=sys.stderr) LG().Log('ERROR', "Unable to unlock user: " + UserName + ". Doing so would result in a passwordless account.") return [-1] Print(usermod_string, file=sys.stderr) LG().Log('INFO', usermod_string) if len(usermodonly_string + usermod_string) > 0: exit_code = os.system( usermod_path + " " + usermodonly_string + usermod_string + " " + UserName) # force password change only if we created the account if PasswordChangeRequired is True and UserName not in old_passwd_entries: exit_code = os.system(chage_path + " -d 0 " + UserName) return [exit_code] def Test(UserName, Ensure, FullName, Description, Password, Disabled, PasswordChangeRequired, HomeDirectory, GroupID): ShowMof('TEST', UserName, Ensure, FullName, Description, Password, Disabled, PasswordChangeRequired, HomeDirectory, GroupID) passwd_entries = None shadow_entries = None passwd_entries = ReadPasswd("/etc/passwd") if passwd_entries is None: return [-1] shadow_entries = ReadPasswd("/etc/shadow") if shadow_entries is None: return [-1] if not Ensure: Ensure = "present" if Ensure == "absent": if UserName not in passwd_entries: return [0] else: Print(UserName + " in passwd_entries", file=sys.stderr) LG().Log('ERROR', UserName + " in passwd_entries") return [-1] elif Ensure == "present": if UserName not in passwd_entries: Print(UserName + " not in passwd_entries", file=sys.stderr) LG().Log('ERROR', UserName + " not in passwd_entries") return [-1] if UserName not in shadow_entries: Print(UserName + " not in shadow_entries", file=sys.stderr) LG().Log('ERROR', UserName + " not in shadow_entries") return [-1] if len(passwd_entries[UserName]) < 6: Print("Unable to read /etc/passwd entry for username: " + UserName, file=sys.stderr) LG().Log( 'ERROR', "Unable to read /etc/passwd entry for username: " + UserName) return [-1] if len(shadow_entries[UserName]) < 8: Print("Unable to read /etc/shadow entry for username: " + UserName, file=sys.stderr) LG().Log( 'ERROR', "Unable to read /etc/shadow entry for username: " + UserName) return [-1] extra_fields = passwd_entries[UserName][3].split(",") if FullName and extra_fields[0] != FullName: Print("Incorrect full name (" + extra_fields[ 0] + "), should be: " + FullName + ", for username: " + UserName, file=sys.stderr) LG().Log('ERROR', "Incorrect full name (" + extra_fields[0] + "), should be: " + FullName + ", for username: " + UserName) return [-1] if Description: if len(extra_fields) < 2: Print("There is no description.", file=sys.stderr) LG().Log('ERROR', "There is no description.") return [-1] elif extra_fields[1] != Description: Print( "Incorrect description for username: " + UserName, file=sys.stderr) LG().Log( 'ERROR', "Incorrect description for username: " + UserName) return [-1] if HomeDirectory and passwd_entries[UserName][4] != HomeDirectory: Print("Home directories do not match", file=sys.stderr) LG().Log('ERROR', "Home directories do not match") return [-1] if GroupID and passwd_entries[UserName][2] != GroupID: Print("GroupID does not match", file=sys.stderr) LG().Log('ERROR', "GroupID does not match") return [-1] if len(Password) > 0: read_password = shadow_entries[UserName][0] if len(read_password) is 0: Print("Password does not match", file=sys.stderr) LG().Log('ERROR', "Password does not match") return [-1] if read_password[0] == "!": read_password = read_password[1:] if read_password != Password: Print("Password does not match", file=sys.stderr) LG().Log('ERROR', "Password does not match") return [-1] if PasswordChangeRequired is True and not PasswordExpired(shadow_entries[UserName]): Print( "PasswordChangeRequired is True and the password is not expired.", file=sys.stderr) LG().Log( 'ERROR', "PasswordChangeRequired is True and the password is not expired.") return [-1] elif PasswordChangeRequired is False and PasswordExpired(shadow_entries[UserName]): Print( "PasswordChangeRequired is False and the password is expired.", file=sys.stderr) LG().Log( 'ERROR', "PasswordChangeRequired is False and the password is expired.") return [-1] if Disabled is True and shadow_entries[UserName][0][0] != "!": Print("Account not disabled", file=sys.stderr) LG().Log('ERROR', "Account not disabled") return [-1] if Disabled is False and shadow_entries[UserName][0][0] == "!": Print("Account disabled", file=sys.stderr) LG().Log('ERROR', "Account disabled") return [-1] return [0] def Get(UserName, Ensure, FullName, Description, Password, Disabled, PasswordChangeRequired, HomeDirectory, GroupID): ShowMof('GET', UserName, Ensure, FullName, Description, Password, Disabled, PasswordChangeRequired, HomeDirectory, GroupID) UserID = '' passwd_entries = None shadow_entries = None passwd_entries = ReadPasswd("/etc/passwd") if passwd_entries is None: return [-1, UserName, Ensure, FullName, Description, Password, Disabled, PasswordChangeRequired, HomeDirectory, GroupID, UserID] shadow_entries = ReadPasswd("/etc/shadow") if shadow_entries is None: return [-1, UserName, Ensure, FullName, Description, Password, Disabled, PasswordChangeRequired, HomeDirectory, GroupID, UserID] exit_code = 0 if UserName not in passwd_entries: FullName = Description = Password = HomeDirectory = GroupID = "" return [exit_code, UserName, Ensure, FullName, Description, Password, Disabled, PasswordChangeRequired, HomeDirectory, GroupID, UserID] extra_fields = passwd_entries[UserName][3].split(",") FullName = extra_fields[0] if len(extra_fields) > 1: Description = extra_fields[1] HomeDirectory = passwd_entries[UserName][4] UserID = passwd_entries[UserName][1] GroupID = passwd_entries[UserName][2] Password = shadow_entries[UserName][0] Disabled = False if len(Password) > 0: if Password[0] == "!": Disabled = True Password = '' # not showing the password. if PasswordExpired(shadow_entries[UserName]): PasswordChangeRequired = True else: PasswordChangeRequired = False return [exit_code, UserName, Ensure, FullName, Description, Password, Disabled, PasswordChangeRequired, HomeDirectory, GroupID, UserID] def GetInventory(UserName, Ensure, FullName, Description, Password, Disabled, PasswordChangeRequired, HomeDirectory, GroupID): Inventory=[] passwd_entries = None passwd_entries = ReadPasswd("/etc/passwd") if passwd_entries is None: return [-1, Inventory] exit_code = 0 d={} for Uname in passwd_entries.keys(): if len(UserName) and not fnmatch.fnmatch(Uname,UserName): continue d['UserName'] = Uname extra_fields = passwd_entries[Uname][3].split(",") d['FullName'] = extra_fields[0] if len(FullName) and not fnmatch.fnmatch(d['FullName'],FullName): continue d['Description'] = '' if len(extra_fields) > 1: d['Description'] = extra_fields[1] if len(Description) and not fnmatch.fnmatch(d['Description'],Description): continue d['HomeDirectory'] = passwd_entries[Uname][4] d['UserID'] = passwd_entries[Uname][1] d['GroupID'] = passwd_entries[Uname][2] d['Disabled'] = False d['Password'] = '' # not showing the password. d['PasswordChangeRequired'] = False Inventory.append(copy.deepcopy(d)) return [exit_code, Inventory]