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