def merge_into(self, other): assert self.get_state() == 'newmember' assert other.get_state() in [ 'shell', 'renew', 'bold', 'expired', 'dead'] assert self.is_current_member() assert not other.is_current_member() issusername = self.get_attribute("tcdnetsoc_ISS_username") or\ other.get_attribute("tcdnetsoc_ISS_username") if other.get_attribute("tcdnetsoc_ISS_username") is not None: assert other.tcdnetsoc_ISS_username == issusername else: other.tcdnetsoc_ISS_username = issusername if self.cn != other.cn: lwarn("Names %s and %s don't match when renewing account %s" % (self.cn, other.cn, other.uid)) other.comment("Renewed by account with non-matching name %s" % self.cn) if self.mail != other.mail: lwarn("Emails %s and %s don't match when renewing account %s" % (self.mail, other.mail, other.uid)) other.comment("Renewed by account with non-matching mail %s" % self.mail) self.tcdnetsoc_membership_year -= current_session() other.tcdnetsoc_membership_year += current_session() self.destroy()
def _register_backlink_attr(fwd, back): b = ValueSet._backlink_attrs if fwd in b: if b[fwd] != back: lwarn("Redeclared backlink for %s (was %s, now %s)" % (fwd, b[fwd], back)) b[fwd] = back
def __init__(self, name, type, matchrule=None, backlink=None): if isinstance(type, list): if not len(type) == 1: raise TypeError("%s is not a supported type" % type) type = type[0] multival = True else: multival = False if matchrule is None: matchrule = default_match(type) self.name = name self.type = type self.multival = multival self.matchrule = matchrule if backlink is not None: ValueSet._register_backlink_attr(self.get_ldap_name(), Attribute._normalise_name( backlink)) attrdesc = self._desc() known = Attribute._known_attrs ldapname = self.get_ldap_name() if ldapname in known: if known[ldapname]._desc() != attrdesc: lwarn("Attribute %s redefined (from %s to %s)" % (name, known[ldapname]._desc(), attrdesc)) known[ldapname] = self
def __init__(self, name, type, matchrule=None, backlink=None): if isinstance(type, list): if not len(type) == 1: raise TypeError("%s is not a supported type" % type) type = type[0] multival = True else: multival = False if matchrule is None: matchrule = default_match(type) self.name = name self.type = type self.multival = multival self.matchrule = matchrule if backlink is not None: ValueSet._register_backlink_attr( self.get_ldap_name(), Attribute._normalise_name(backlink)) attrdesc = self._desc() known = Attribute._known_attrs ldapname = self.get_ldap_name() if ldapname in known: if known[ldapname]._desc() != attrdesc: lwarn("Attribute %s redefined (from %s to %s)" % (name, known[ldapname]._desc(), attrdesc)) known[ldapname] = self
def get_attribute(name): '''Lookup an attribute of a given name''' n = Attribute._normalise_name(name) known = Attribute._known_attrs if n in known: return known[n] else: lwarn("Undeclared attribute %s. \ Defaulting to assuming it's a single-valued string." % name) return Attribute(name, str, match_exact_or_substring)
def reset_password(self): if not self.has_account(): raise Exception("User account is disabled,\ password cannot be reset") pw = generate_password() self.passwd(pw) addr = self.get_attribute("mail") if addr is None: lwarn("No mail address recorded for user %s (%s),\ can't send password reset message" % (self.get_attribute("uid"), self.get_attribute("cn"))) else: sm.sendmail("password_reset", to=addr, username=self.uid, password=pw)
def set_state(self, newst, newpasswd=None): assert newst in User.states st = self.get_state() if st == newst: return if st == "newmember" and newst not in\ ["archived", "shell", "newmember"]: raise Exception("User doesn't have an account,\ so it can't be set to %s" % newst) if (st, newst) == ("archived", "newmember"): self.tcdnetsoc_saved_password = "******" elif newst == "newmember": raise Exception("that makes no sense") elif newst == "archived": # self.objectClass -= "posixAccount" # # FIXME: remove other privileges as well?? # if self.has_priv("shell"): # Privilege("shell").member -= self # del self.userPassword # return raise Exception("archiving accounts not yet implemented") elif st == "archived": raise Exception("un-archiving accounts not yet implemented") # if self._has_disabled_shell(): # prevstate = self.loginShell[len(User.disabled_shells_base):] # if newst != prevstate: # raise Exception("Trying to change state of %s from # disabled to %s, \ # although account was %s" % (self, newst, prevstate)) # # assert not self.has_priv("shell") # if not PersonalGroup(self.uid).exists(): # PersonalGroup.create(cn=self.uid, # objectClass=["tcdnetsoc-group"], # gidNumber=self.uidNumber, # member=[self]) # self.gidNumber = self.uidNumber # self.homeDirectory = User.homedir_pattern % self.uid # self.objectClass += "posixAccount" # Privilege("shell").member += self # Bouncer state is for alumni who have chosen not to have a shell account elif newst == "bouncer": if st != "shell": raise Exception("user must have had shell account as \ to have bouncer as implemented here") else: # User had shell, now grant user bouncer priv and # lock user's shell. Use SSH and pam_access to lock # user's access to commands self.grant_priv("bouncer") self.tcdnetsoc_temp_loginShell = self.loginShell self.loginShell = '/usr/bin/passwd' else: # Effectively default outcome if st == "newmember": del self.tcdnetsoc_saved_password else: Privilege(st).member -= self Privilege(newst).member += self if newst == "shell": # ensure GID is set if self.get_attribute('gidNumber') is None: self.gidNumber = self.uidNumber # ensure homedir is set if self.get_attribute('homeDirectory') is None: self.homeDirectory = '/home/' + self.uid # ensure group exists self.create_personal_group() self.objectClass += 'posixAccount' # (re-)enable Samba if st == 'newmember': self.setup_samba_account() else: self.objectClass += 'sambaSamAccount' if st == 'newmember': self.setup_shadow_account() # restore old password (if any) if newpasswd is not None: self.passwd(newpasswd) elif self.get_attribute( "tcdnetsoc_saved_password" ) is not None: self.userPassword = self.tcdnetsoc_saved_password else: pwd = generate_password() lwarn("Setting password for %s to %s" % (self.uid, pwd)) self.passwd(pwd) # set shell if necessary if self.get_attribute("loginShell") is None or \ "special_shell" in self.loginShell or \ st in ["bold", "dead"]: # get AUP-violating users to re-accept AUP self.loginShell = User.first_login_shell # expired and newmember users get webspace # renew users didn't lose it # and bold/dead users don't get it without admin intervention if st in ["expired", "newmember"]: self.grant_priv("webspace") self.reset_mysql_pw() # FIXME quotas else: # can't be a new member if the account # is being set to [rewew,expired,bold,dead] # since you need to have had an account # for those things to happen assert st != "newmember" # removing shell, save old password if self.can_bind(): self.tcdnetsoc_saved_password = self.userPassword del self.userPassword # possibly remove privileges if newst in ["bold", "dead"]: for g in list(self.memberOf): if isinstance(g, Privilege) and g.cn != newst: self.memberOf -= g # remove samba access if 'sambaSamAccount' in self.objectClass: self.objectClass -= 'sambaSamAccount'