# passwd.py - lookup functions for user account information # # Copyright (C) 2010 Arthur de Jong # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301 USA import constants import common import cfg import logging import ldap import ldap.filter class PasswdRequest(common.Request): attmap = { 'uid': 'uid', 'userPassword': 'userPassword', 'uidNumber': 'uidNumber', 'gidNumber': 'gidNumber', 'gecos': '"${gecos:-$cn}"', 'cn': 'cn', 'homeDirectory': 'homeDirectory', 'loginShell': 'loginShell', 'objectClass': 'objectClass' } filter = '(objectClass=posixAccount)' attmap_passwd_uid = 'uid' attmap_passwd_userPassword = 'userPassword' attmap_passwd_uidNumber = 'uidNumber' attmap_passwd_gidNumber = 'gidNumber' attmap_passwd_gecos = '"${gecos:-$cn}"' attmap_passwd_homeDirectory = 'homeDirectory' attmap_passwd_loginShell = 'loginShell' # these should be removed attmap_passwd_cn = 'cn' attributes = ( 'uid', 'userPassword', 'uidNumber', 'gidNumber', 'gecos', 'cn', 'homeDirectory', 'loginShell', 'objectClass' ) bases = ( 'ou=people,dc=test,dc=tld', ) def write(self, entry): dn, attributes = entry # get uid attribute and check against requested user name names = attributes.get('uid', []) if self.name: if self.name not in names: return names = ( self.name, ) # get user password entry if 'shadowAccount' in attributes.get('objectClass', []): passwd = 'x' else: passwd = '*'; # get numeric user and group ids uids = ( self.uid, ) if self.uid else attributes.get(self.attmap_passwd_uidNumber, []) uids = [ int(x) for x in uids ] ( gid, ) = attributes[self.attmap_passwd_gidNumber] gid = int(gid) # FIXME: use expression here gecos = attributes.get(self.attmap_passwd_gecos, [None])[0] or attributes.get(self.attmap_passwd_cn, [''])[0] ( home, ) = attributes.get(self.attmap_passwd_homeDirectory, ['']) ( shell, ) = attributes.get(self.attmap_passwd_loginShell, ['']) for name in names: if not common.isvalidname(name): print 'Warning: passwd entry %s contains invalid user name: "%s"' % ( dn, name ) else: for uid in uids: #print '%s:%s:%d:%d:%s:%s:%s' % ( name, passwd, uid, gid, gecos, home, shell ) self.fp.write_int32(constants.NSLCD_RESULT_BEGIN) self.fp.write_string(name) self.fp.write_string(passwd) self.fp.write_uid_t(uid) self.fp.write_gid_t(gid) self.fp.write_string(gecos) self.fp.write_string(home) self.fp.write_string(shell) class PasswdByNameRequest(PasswdRequest): action = constants.NSLCD_ACTION_PASSWD_BYNAME def read_parameters(self): self.name = self.fp.read_string() common.validate_name(self.name) def mk_filter(self): return '(&%s(%s=%s))' % ( self.filter, self.attmap_passwd_uid, ldap.filter.escape_filter_chars(self.name) ) class PasswdByUidRequest(PasswdRequest): action = constants.NSLCD_ACTION_PASSWD_BYUID def read_parameters(self): self.uid = self.fp.read_uid_t() def mk_filter(self): return '(&%s(%s=%d))' % ( self.filter, self.attmap_passwd_uidNumber, self.uid ) class PasswdAllRequest(PasswdRequest): action = constants.NSLCD_ACTION_PASSWD_ALL def do_search(conn, filter=None, base=None): mybases = ( base, ) if base else PasswdRequest.bases filter = filter or PasswdRequest.filter # perform a search for each search base for base in mybases: # do the LDAP search try: res = conn.search_s(base, PasswdRequest.scope, filter, [PasswdRequest.attmap_passwd_uid]) for entry in res: if entry[0]: yield entry except ldap.NO_SUCH_OBJECT: # FIXME: log message pass def uid2entry(conn, uid): """Look up the user by uid and return the LDAP entry or None if the user was not found.""" myfilter = '(&%s(%s=%s))' % ( PasswdRequest.filter, PasswdRequest.attmap_passwd_uid, ldap.filter.escape_filter_chars(uid) ) for dn, attributes in do_search(conn, myfilter): if uid in attributes[PasswdRequest.attmap_passwd_uid]: return dn, attributes def uid2dn(conn, uid): """Look up the user by uid and return the DN or None if the user was not found.""" x = uid2entry(conn, uid) if x is not None: return x[0] def dn2uid(conn, dn): """Look up the user by dn and return a uid or None if the user was not found.""" try: for dn, attributes in do_search(conn, base=dn): return attributes[PasswdRequest.attmap_passwd_uid][0] except ldap.NO_SUCH_OBJECT: return None