xref: /netbsd-src/external/bsd/openldap/dist/contrib/slapd-modules/nssov/group.c (revision 274254cdae52594c1aa480a736aef78313d15c9c)
1 /* group.c - group lookup routines */
2 /* $OpenLDAP: pkg/ldap/contrib/slapd-modules/nssov/group.c,v 1.1.2.1 2008/07/08 18:53:57 quanah Exp $ */
3 /*
4  * Copyright 2008 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 		if ( ! ( (name->bv_val[i]>='A' && name->bv_val[i] <= 'Z') ||
125 						 (name->bv_val[i]>='a' && name->bv_val[i] <= 'z') ||
126 						 (name->bv_val[i]>='0' && name->bv_val[i] <= '9') ||
127 						 name->bv_val[i]=='.' || name->bv_val[i]=='_' || name->bv_val[i]=='-') )
128 			return 0;
129 	}
130 	/* no test failed so it must be good */
131 	return -1;
132 }
133 
134 static int write_group(nssov_group_cbp *cbp,Entry *entry)
135 {
136 	struct berval tmparr[2], tmpgid[2];
137 	struct berval *names,*gids,*members;
138 	struct berval passwd = {0};
139 	Attribute *a;
140 	int i,j,nummembers,rc;
141 
142 	/* get group name (cn) */
143 	if (BER_BVISNULL(&cbp->name))
144 	{
145 		a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[CN_KEY].an_desc);
146 		if ( !a )
147 		{
148 			Debug(LDAP_DEBUG_ANY,"group entry %s does not contain %s value",
149 					entry->e_name.bv_val, cbp->mi->mi_attrs[CN_KEY].an_desc->ad_cname.bv_val,0);
150 			return 0;
151 		}
152 		names = a->a_vals;
153 	}
154 	else
155 	{
156 		names=tmparr;
157 		names[0]=cbp->name;
158 		BER_BVZERO(&names[1]);
159 	}
160 	/* get the group id(s) */
161 	if (BER_BVISNULL(&cbp->gidnum))
162 	{
163 		a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[GID_KEY].an_desc);
164 		if ( !a )
165 		{
166 			Debug(LDAP_DEBUG_ANY,"group entry %s does not contain %s value",
167 					entry->e_name.bv_val, cbp->mi->mi_attrs[GID_KEY].an_desc->ad_cname.bv_val,0);
168 			return 0;
169 		}
170 		gids = a->a_vals;
171 	}
172 	else
173 	{
174 		gids=tmpgid;
175 		gids[0]=cbp->gidnum;
176 		BER_BVZERO(&gids[1]);
177 	}
178 	/* get group passwd (userPassword) (use only first entry) */
179 	a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[PWD_KEY].an_desc);
180 	if (a)
181 		get_userpassword(&a->a_vals[0], &passwd);
182 	if (BER_BVISNULL(&passwd))
183 		passwd=default_group_userPassword;
184 	/* get group members (memberUid&uniqueMember) */
185 	if (cbp->wantmembers) {
186 		Attribute *b;
187 		i = 0; j = 0;
188 		a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[UID_KEY].an_desc);
189 		b = attr_find(entry->e_attrs, cbp->mi->mi_attrs[MEM_KEY].an_desc);
190 		if ( a )
191 			i += a->a_numvals;
192 		if ( b )
193 			i += b->a_numvals;
194 		if ( i )
195 			members = cbp->op->o_tmpalloc( (i+1) * sizeof(struct berval), cbp->op->o_tmpmemctx );
196 
197 		if ( a ) {
198 			for (i=0; i<a->a_numvals; i++) {
199 				if (isvalidusername(&a->a_vals[i])) {
200 					ber_dupbv_x(&members[j],&a->a_vals[i],cbp->op->o_tmpmemctx);
201 					j++;
202 				}
203 			}
204 		}
205 		a = b;
206 		if ( a ) {
207 			for (i=0; i<a->a_numvals; i++) {
208 				if (nssov_dn2uid(cbp->op,cbp->ni,&a->a_nvals[i],&members[j]))
209 					j++;
210 			}
211 		}
212 		nummembers = j;
213 		BER_BVZERO(&members[j]);
214 	} else {
215 		members=NULL;
216 		nummembers = 0;
217 	}
218 	/* write entries for all names and gids */
219 	for (i=0;!BER_BVISNULL(&names[i]);i++)
220 	{
221 		if (!isvalidgroupname(&names[i]))
222 		{
223 			Debug(LDAP_DEBUG_ANY,"nssov: group entry %s contains invalid group name: \"%s\"",
224 													entry->e_name.bv_val,names[i].bv_val,0);
225 		}
226 		else
227 		{
228 			for (j=0;!BER_BVISNULL(&gids[j]);j++)
229 			{
230 				char *tmp;
231 				int tmpint32;
232 				gid_t gid;
233 				gid = strtol(gids[j].bv_val, &tmp, 0);
234 				if ( *tmp ) {
235 					Debug(LDAP_DEBUG_ANY,"nssov: group entry %s contains non-numeric %s value: \"%s\"",
236 						entry->e_name.bv_val, cbp->mi->mi_attrs[GID_KEY].an_desc->ad_cname.bv_val,
237 						names[i].bv_val);
238 					continue;
239 				}
240 				WRITE_INT32(cbp->fp,NSLCD_RESULT_SUCCESS);
241 				WRITE_BERVAL(cbp->fp,&names[i]);
242 				WRITE_BERVAL(cbp->fp,&passwd);
243 				WRITE_TYPE(cbp->fp,gid,gid_t);
244 				/* write a list of values */
245 				WRITE_INT32(cbp->fp,nummembers);
246 				if (nummembers)
247 				{
248 					int k;
249 					for (k=0;k<nummembers;k++) {
250 						WRITE_BERVAL(cbp->fp,&members[k]);
251 					}
252 				}
253 			}
254 		}
255 	}
256 	/* free and return */
257 	if (members!=NULL)
258 		ber_bvarray_free_x( members, cbp->op->o_tmpmemctx );
259 	return rc;
260 }
261 
262 NSSOV_CB(group)
263 
264 NSSOV_HANDLE(
265 	group,byname,
266 	char fbuf[1024];
267 	struct berval filter = {sizeof(fbuf)};
268 	filter.bv_val = fbuf;
269 	READ_STRING_BUF2(fp,cbp.buf,sizeof(cbp.buf));
270 	cbp.name.bv_len = tmpint32;
271 	cbp.name.bv_val = cbp.buf;
272 	if (!isvalidgroupname(&cbp.name)) {
273 		Debug(LDAP_DEBUG_ANY,"nssov_group_byname(%s): invalid group name",cbp.name.bv_val,0,0);
274 		return -1;
275 	}
276 	cbp.wantmembers = 1;
277 	cbp.ni = ni;
278 	BER_BVZERO(&cbp.gidnum);
279 	BER_BVZERO(&cbp.user);,
280 	Debug(LDAP_DEBUG_TRACE,"nslcd_group_byname(%s)",cbp.name.bv_val,0,0);,
281 	NSLCD_ACTION_GROUP_BYNAME,
282 	nssov_filter_byname(cbp.mi,CN_KEY,&cbp.name,&filter)
283 )
284 
285 NSSOV_HANDLE(
286 	group,bygid,
287 	gid_t gid;
288 	char fbuf[1024];
289 	struct berval filter = {sizeof(fbuf)};
290 	filter.bv_val = fbuf;
291 	READ_TYPE(fp,gid,gid_t);
292 	cbp.gidnum.bv_val = cbp.buf;
293 	cbp.gidnum.bv_len = snprintf(cbp.buf,sizeof(cbp.buf),"%d",gid);
294 	cbp.wantmembers = 1;
295 	cbp.ni = ni;
296 	BER_BVZERO(&cbp.name);
297 	BER_BVZERO(&cbp.user);,
298 	Debug(LDAP_DEBUG_TRACE,"nssov_group_bygid(%s)",cbp.gidnum.bv_val,0,0);,
299 	NSLCD_ACTION_GROUP_BYGID,
300 	nssov_filter_byid(cbp.mi,GID_KEY,&cbp.gidnum,&filter)
301 )
302 
303 NSSOV_HANDLE(
304 	group,bymember,
305 	char fbuf[1024];
306 	struct berval filter = {sizeof(fbuf)};
307 	filter.bv_val = fbuf;
308 	READ_STRING_BUF2(fp,cbp.buf,sizeof(cbp.buf));
309 	cbp.user.bv_len = tmpint32;
310 	cbp.user.bv_val = cbp.buf;
311 	if (!isvalidusername(&cbp.user)) {
312 		Debug(LDAP_DEBUG_ANY,"nssov_group_bymember(%s): invalid user name",cbp.user.bv_val,0,0);
313 		return -1;
314 	}
315 	cbp.wantmembers = 0;
316 	cbp.ni = ni;
317 	BER_BVZERO(&cbp.name);
318 	BER_BVZERO(&cbp.gidnum);,
319 	Debug(LDAP_DEBUG_TRACE,"nssov_group_bymember(%s)",cbp.user.bv_val,0,0);,
320 	NSLCD_ACTION_GROUP_BYMEMBER,
321 	mkfilter_group_bymember(&cbp,&filter)
322 )
323 
324 NSSOV_HANDLE(
325 	group,all,
326 	struct berval filter;
327 	/* no parameters to read */
328 	cbp.wantmembers = 1;
329 	cbp.ni = ni;
330 	BER_BVZERO(&cbp.name);
331 	BER_BVZERO(&cbp.gidnum);,
332 	Debug(LDAP_DEBUG_TRACE,"nssov_group_all()",0,0,0);,
333 	NSLCD_ACTION_GROUP_ALL,
334 	(filter=cbp.mi->mi_filter,0)
335 )
336