]> git.sur5r.net Git - openldap/blob - contrib/slapd-modules/nssov/group.c
866dcd6a108fb00da0655917a345bfb73f8c501b
[openldap] / contrib / slapd-modules / nssov / group.c
1 /* group.c - group lookup routines */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 2008-2009 by Howard Chu, Symas Corp.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted only as authorized by the OpenLDAP
9  * Public License.
10  *
11  * A copy of this license is available in the file LICENSE in the
12  * top-level directory of the distribution or, alternatively, at
13  * <http://www.OpenLDAP.org/license.html>.
14  */
15 /*
16  * This code references portions of the nss-ldapd package
17  * written by Arthur de Jong. The nss-ldapd code was forked
18  * from the nss-ldap library written by Luke Howard.
19  */
20
21 #include "nssov.h"
22
23 /* for gid_t */
24 #include <grp.h>
25
26 /* ( nisSchema.2.2 NAME 'posixGroup' SUP top STRUCTURAL
27  *   DESC 'Abstraction of a group of accounts'
28  *   MUST ( cn $ gidNumber )
29  *   MAY ( userPassword $ memberUid $ description ) )
30  *
31  * apart from that the above the uniqueMember attributes may be
32  * supported in a coming release (they map to DNs, which is an extra
33  * lookup step)
34  *
35  * using nested groups (groups that are member of a group) is currently
36  * not supported, this may be added in a later release
37  */
38
39 /* the basic search filter for searches */
40 static struct berval group_filter = BER_BVC("(objectClass=posixGroup)");
41
42 /* the attributes to request with searches */
43 static struct berval group_keys[] = {
44         BER_BVC("cn"),
45         BER_BVC("userPassword"),
46         BER_BVC("gidNumber"),
47         BER_BVC("memberUid"),
48         BER_BVC("uniqueMember"),
49         BER_BVNULL
50 };
51
52 #define CN_KEY  0
53 #define PWD_KEY 1
54 #define GID_KEY 2
55 #define UID_KEY 3
56 #define MEM_KEY 4
57
58 /* default values for attributes */
59 static struct berval default_group_userPassword     = BER_BVC("*"); /* unmatchable */
60
61 NSSOV_CBPRIV(group,
62         nssov_info *ni;
63         char buf[256];
64         struct berval name;
65         struct berval gidnum;
66         struct berval user;
67         int wantmembers;);
68
69 /* create a search filter for searching a group entry
70          by member uid, return -1 on errors */
71 static int mkfilter_group_bymember(nssov_group_cbp *cbp,struct berval *buf)
72 {
73         struct berval dn;
74         /* try to translate uid to DN */
75         nssov_uid2dn(cbp->op,cbp->ni,&cbp->user,&dn);
76         if (BER_BVISNULL(&dn)) {
77                 if (cbp->user.bv_len + cbp->mi->mi_filter.bv_len + cbp->mi->mi_attrs[UID_KEY].an_desc->ad_cname.bv_len + 6 >
78                         buf->bv_len )
79                         return -1;
80                 buf->bv_len = snprintf(buf->bv_val, buf->bv_len, "(&%s(%s=%s))",
81                         cbp->mi->mi_filter.bv_val, cbp->mi->mi_attrs[UID_KEY].an_desc->ad_cname.bv_val,
82                         cbp->user.bv_val );
83         } else { /* also lookup using user DN */
84                 if (cbp->user.bv_len + cbp->mi->mi_filter.bv_len + cbp->mi->mi_attrs[UID_KEY].an_desc->ad_cname.bv_len +
85                         dn.bv_len + cbp->mi->mi_attrs[MEM_KEY].an_desc->ad_cname.bv_len + 12 > buf->bv_len )
86                         return -1;
87                 buf->bv_len = snprintf(buf->bv_val, buf->bv_len, "(&%s(|(%s=%s)(%s=%s)))",
88                         cbp->mi->mi_filter.bv_val,
89                         cbp->mi->mi_attrs[UID_KEY].an_desc->ad_cname.bv_val, cbp->user.bv_val,
90                         cbp->mi->mi_attrs[MEM_KEY].an_desc->ad_cname.bv_val, dn.bv_val );
91         }
92         return 0;
93 }
94
95 NSSOV_INIT(group)
96
97 /*
98          Checks to see if the specified name is a valid group name.
99
100          This test is based on the definition from POSIX (IEEE Std 1003.1, 2004,
101          3.189 Group Name and 3.276 Portable Filename Character Set):
102          http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap03.html#tag_03_189
103          http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap03.html#tag_03_276
104
105          The standard defines group names valid if they only contain characters from
106          the set [A-Za-z0-9._-] where the hyphen should not be used as first
107          character.
108 */
109 static int isvalidgroupname(struct berval *name)
110 {
111         int i;
112
113         if ( !name->bv_val || !name->bv_len )
114                 return 0;
115         /* check first character */
116         if ( ! ( (name->bv_val[0]>='A' && name->bv_val[0] <= 'Z') ||
117                                          (name->bv_val[0]>='a' && name->bv_val[0] <= 'z') ||
118                                          (name->bv_val[0]>='0' && name->bv_val[0] <= '9') ||
119                                          name->bv_val[0]=='.' || name->bv_val[0]=='_' ) )
120                 return 0;
121         /* check other characters */
122         for (i=1;i<name->bv_len;i++)
123         {
124 #ifndef STRICT_GROUPS
125                 /* allow spaces too */
126                 if (name->bv_val[i] == ' ') continue;
127 #endif
128                 if ( ! ( (name->bv_val[i]>='A' && name->bv_val[i] <= 'Z') ||
129                                                  (name->bv_val[i]>='a' && name->bv_val[i] <= 'z') ||
130                                                  (name->bv_val[i]>='0' && name->bv_val[i] <= '9') ||
131                                                  name->bv_val[i]=='.' || name->bv_val[i]=='_' || name->bv_val[i]=='-') )
132                         return 0;
133         }
134         /* no test failed so it must be good */
135         return -1;
136 }
137
138 static int write_group(nssov_group_cbp *cbp,Entry *entry)
139 {
140         struct berval tmparr[2], tmpgid[2];
141         struct berval *names,*gids,*members;
142         struct berval passwd = {0};
143         Attribute *a;
144         int i,j,nummembers,rc;
145
146         /* get group name (cn) */
147         if (BER_BVISNULL(&cbp->name))
148         {
149                 a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[CN_KEY].an_desc);
150                 if ( !a )
151                 {
152                         Debug(LDAP_DEBUG_ANY,"group entry %s does not contain %s value\n",
153                                         entry->e_name.bv_val, cbp->mi->mi_attrs[CN_KEY].an_desc->ad_cname.bv_val,0);
154                         return 0;
155                 }
156                 names = a->a_vals;
157         }
158         else
159         {
160                 names=tmparr;
161                 names[0]=cbp->name;
162                 BER_BVZERO(&names[1]);
163         }
164         /* get the group id(s) */
165         if (BER_BVISNULL(&cbp->gidnum))
166         {
167                 a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[GID_KEY].an_desc);
168                 if ( !a )
169                 {
170                         Debug(LDAP_DEBUG_ANY,"group entry %s does not contain %s value\n",
171                                         entry->e_name.bv_val, cbp->mi->mi_attrs[GID_KEY].an_desc->ad_cname.bv_val,0);
172                         return 0;
173                 }
174                 gids = a->a_vals;
175         }
176         else
177         {
178                 gids=tmpgid;
179                 gids[0]=cbp->gidnum;
180                 BER_BVZERO(&gids[1]);
181         }
182         /* get group passwd (userPassword) (use only first entry) */
183         a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[PWD_KEY].an_desc);
184         if (a)
185                 get_userpassword(&a->a_vals[0], &passwd);
186         if (BER_BVISNULL(&passwd))
187                 passwd=default_group_userPassword;
188         /* get group members (memberUid&uniqueMember) */
189         if (cbp->wantmembers) {
190                 Attribute *b;
191                 i = 0; j = 0;
192                 a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[UID_KEY].an_desc);
193                 b = attr_find(entry->e_attrs, cbp->mi->mi_attrs[MEM_KEY].an_desc);
194                 if ( a )
195                         i += a->a_numvals;
196                 if ( b )
197                         i += b->a_numvals;
198                 if ( i ) {
199                         members = cbp->op->o_tmpalloc( (i+1) * sizeof(struct berval), cbp->op->o_tmpmemctx );
200                         
201                         if ( a ) {
202                                 for (i=0; i<a->a_numvals; i++) {
203                                         if (isvalidusername(&a->a_vals[i])) {
204                                                 ber_dupbv_x(&members[j],&a->a_vals[i],cbp->op->o_tmpmemctx);
205                                                 j++;
206                                         }
207                                 }
208                         }
209                         a = b;
210                         if ( a ) {
211                                 for (i=0; i<a->a_numvals; i++) {
212                                         if (nssov_dn2uid(cbp->op,cbp->ni,&a->a_nvals[i],&members[j]))
213                                                 j++;
214                                 }
215                         }
216                         nummembers = j;
217                         BER_BVZERO(&members[j]);
218                 } else {
219                         members=NULL;
220                         nummembers = 0;
221                 }
222
223         } else {
224                 members=NULL;
225                 nummembers = 0;
226         }
227         /* write entries for all names and gids */
228         for (i=0;!BER_BVISNULL(&names[i]);i++)
229         {
230                 if (!isvalidgroupname(&names[i]))
231                 {
232                         Debug(LDAP_DEBUG_ANY,"nssov: group entry %s contains invalid group name: \"%s\"\n",
233                                                                                                         entry->e_name.bv_val,names[i].bv_val,0);
234                 }
235                 else
236                 {
237                         for (j=0;!BER_BVISNULL(&gids[j]);j++)
238                         {
239                                 char *tmp;
240                                 int tmpint32;
241                                 gid_t gid;
242                                 gid = strtol(gids[j].bv_val, &tmp, 0);
243                                 if ( *tmp ) {
244                                         Debug(LDAP_DEBUG_ANY,"nssov: group entry %s contains non-numeric %s value: \"%s\"\n",
245                                                 entry->e_name.bv_val, cbp->mi->mi_attrs[GID_KEY].an_desc->ad_cname.bv_val,
246                                                 names[i].bv_val);
247                                         continue;
248                                 }
249                                 WRITE_INT32(cbp->fp,NSLCD_RESULT_SUCCESS);
250                                 WRITE_BERVAL(cbp->fp,&names[i]);
251                                 WRITE_BERVAL(cbp->fp,&passwd);
252                                 WRITE_TYPE(cbp->fp,gid,gid_t);
253                                 /* write a list of values */
254                                 WRITE_INT32(cbp->fp,nummembers);
255                                 if (nummembers)
256                                 {
257                                         int k;
258                                         for (k=0;k<nummembers;k++) {
259                                                 WRITE_BERVAL(cbp->fp,&members[k]);
260                                         }
261                                 }
262                         }
263                 }
264         }
265         /* free and return */
266         if (members!=NULL)
267                 ber_bvarray_free_x( members, cbp->op->o_tmpmemctx );
268         return rc;
269 }
270
271 NSSOV_CB(group)
272
273 NSSOV_HANDLE(
274         group,byname,
275         char fbuf[1024];
276         struct berval filter = {sizeof(fbuf)};
277         filter.bv_val = fbuf;
278         READ_STRING_BUF2(fp,cbp.buf,sizeof(cbp.buf));
279         cbp.name.bv_len = tmpint32;
280         cbp.name.bv_val = cbp.buf;
281         if (!isvalidgroupname(&cbp.name)) {
282                 Debug(LDAP_DEBUG_ANY,"nssov_group_byname(%s): invalid group name\n",cbp.name.bv_val,0,0);
283                 return -1;
284         }
285         cbp.wantmembers = 1;
286         cbp.ni = ni;
287         BER_BVZERO(&cbp.gidnum);
288         BER_BVZERO(&cbp.user);,
289         Debug(LDAP_DEBUG_TRACE,"nslcd_group_byname(%s)\n",cbp.name.bv_val,0,0);,
290         NSLCD_ACTION_GROUP_BYNAME,
291         nssov_filter_byname(cbp.mi,CN_KEY,&cbp.name,&filter)
292 )
293
294 NSSOV_HANDLE(
295         group,bygid,
296         gid_t gid;
297         char fbuf[1024];
298         struct berval filter = {sizeof(fbuf)};
299         filter.bv_val = fbuf;
300         READ_TYPE(fp,gid,gid_t);
301         cbp.gidnum.bv_val = cbp.buf;
302         cbp.gidnum.bv_len = snprintf(cbp.buf,sizeof(cbp.buf),"%d",gid);
303         cbp.wantmembers = 1;
304         cbp.ni = ni;
305         BER_BVZERO(&cbp.name);
306         BER_BVZERO(&cbp.user);,
307         Debug(LDAP_DEBUG_TRACE,"nssov_group_bygid(%s)\n",cbp.gidnum.bv_val,0,0);,
308         NSLCD_ACTION_GROUP_BYGID,
309         nssov_filter_byid(cbp.mi,GID_KEY,&cbp.gidnum,&filter)
310 )
311
312 NSSOV_HANDLE(
313         group,bymember,
314         char fbuf[1024];
315         struct berval filter = {sizeof(fbuf)};
316         filter.bv_val = fbuf;
317         READ_STRING_BUF2(fp,cbp.buf,sizeof(cbp.buf));
318         cbp.user.bv_len = tmpint32;
319         cbp.user.bv_val = cbp.buf;
320         if (!isvalidusername(&cbp.user)) {
321                 Debug(LDAP_DEBUG_ANY,"nssov_group_bymember(%s): invalid user name\n",cbp.user.bv_val,0,0);
322                 return -1;
323         }
324         cbp.wantmembers = 0;
325         cbp.ni = ni;
326         BER_BVZERO(&cbp.name);
327         BER_BVZERO(&cbp.gidnum);,
328         Debug(LDAP_DEBUG_TRACE,"nssov_group_bymember(%s)\n",cbp.user.bv_val,0,0);,
329         NSLCD_ACTION_GROUP_BYMEMBER,
330         mkfilter_group_bymember(&cbp,&filter)
331 )
332
333 NSSOV_HANDLE(
334         group,all,
335         struct berval filter;
336         /* no parameters to read */
337         cbp.wantmembers = 1;
338         cbp.ni = ni;
339         BER_BVZERO(&cbp.name);
340         BER_BVZERO(&cbp.gidnum);,
341         Debug(LDAP_DEBUG_TRACE,"nssov_group_all()\n",0,0,0);,
342         NSLCD_ACTION_GROUP_ALL,
343         (filter=cbp.mi->mi_filter,0)
344 )