Arthur de Jong

Open Source / Free Software developer

summaryrefslogtreecommitdiffstats
path: root/pynslcd/group.py
blob: 4f85441433efdc18b35fd9096fa32e708d0de5eb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174

# group.py - group entry lookup routines
#
# 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


def clean(lst):
    for i in lst:
        yield i.replace('\0', '')

class GroupRequest(common.Request):

    filter = '(|(objectClass=posixGroup)(objectClass=groupOfUniqueNames))'

    attmap_group_cn           = 'cn'
    attmap_group_userPassword = 'userPassword'
    attmap_group_gidNumber    = 'gidNumber'
    attmap_group_memberUid    = 'memberUid'
    attmap_group_uniqueMember = 'uniqueMember'

    attributes = ( 'cn', 'userPassword', 'gidNumber', 'memberUid',
                   'uniqueMember' )

    wantmembers = True

    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
        passwd = '*'
        # get numeric user and group ids
        uids = ( self.uid, ) if self.uid else attributes.get(self.attmap_group_uidNumber, [])
        uids = [ int(x) for x in uids ]
        ( gid, ) = attributes[self.attmap_group_gidNumber]
        gid = int(gid)
        # FIXME: use expression here
        gecos = attributes.get(self.attmap_group_gecos, [None])[0] or attributes.get(self.attmap_group_cn, [''])[0]
        ( home, ) = attributes.get(self.attmap_group_homeDirectory, [''])
        ( shell, ) = attributes.get(self.attmap_group_loginShell, [''])
        for name in names:
            if not common.isvalidname(name):
                print 'Warning: group entry %s contains invalid user name: "%s"' % ( dn, name )
            else:
                for uid in uids:
                    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)

    def write(self, entry):
        dn, attributes = entry
        # get group names and check against requested group name
        names = attributes.get(self.attmap_group_cn, [])
        if self.name:
            if self.name not in names:
                return
            names = ( self.name, )
        # get group group password
        ( passwd, ) = attributes.get(self.attmap_group_userPassword, ['*'])
        # get group id(s)
        gids = ( self.gid, ) if self.gid else attributes.get(self.attmap_group_gidNumber, [])
        gids = [ int(x) for x in gids ]
        # build member list
        members = set()
        if self.wantmembers:
            # add the memberUid values
            for member in clean(attributes.get(self.attmap_group_memberUid, [])):
                #print 'found member %r' % member
                if common.isvalidname(member):
                    members.add(member)
            # translate and add the uniqueMember values
            from passwd import dn2uid
            for memberdn in clean(attributes.get(self.attmap_group_uniqueMember, [])):
                member = dn2uid(self.conn, memberdn)
                #print 'found memberdn %r, member=%r' % ( memberdn, member)
                if member:
                    members.add(member)
        # actually return the results
        for name in names:
            if not common.isvalidname(name):
                print 'Warning: group entry %s contains invalid group name: "%s"' % ( dn, name )
            else:
                for gid in gids:
                    self.fp.write_int32(constants.NSLCD_RESULT_BEGIN)
                    self.fp.write_string(name)
                    self.fp.write_string(passwd)
                    self.fp.write_gid_t(gid)
                    self.fp.write_stringlist(members)


class GroupByNameRequest(GroupRequest):

    action = constants.NSLCD_ACTION_GROUP_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_group_cn, ldap.filter.escape_filter_chars(self.name) )


class GroupByGidRequest(GroupRequest):

    action = constants.NSLCD_ACTION_GROUP_BYGID

    def read_parameters(self):
        self.gid = self.fp.read_gid_t()

    def mk_filter(self):
        return '(&%s(%s=%d))' % ( self.filter,
                  self.attmap_group_gidNumber, self.gid )


class GroupByMemberRequest(GroupRequest):

    action = constants.NSLCD_ACTION_GROUP_BYMEMBER
    wantmembers = False
    attributes = ( 'cn', 'userPassword', 'gidNumber' )

    def read_parameters(self):
        self.memberuid = self.fp.read_string()
        common.validate_name(self.memberuid)

    def mk_filter(self):
        # try to translate uid to DN
        # TODO: only do this if memberuid attribute is mapped
        import passwd
        dn = passwd.uid2dn(self.conn, self.memberuid)
        if dn:
            return '(&%s(|(%s=%s)(%s=%s)))' % ( self.filter,
                      self.attmap_group_memberUid, ldap.filter.escape_filter_chars(self.memberuid),
                      self.attmap_group_uniqueMember, ldap.filter.escape_filter_chars(dn) )
        else:
            return '(&%s(%s=%s))' % ( self.filter,
                      self.attmap_group_memberUid, ldap.filter.escape_filter_chars(self.memberuid) )


class GroupAllRequest(GroupRequest):

    action = constants.NSLCD_ACTION_GROUP_ALL