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