1 /* group.c - group lookup routines */
4 * Copyright 2008-2009 by Howard Chu, Symas Corp.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted only as authorized by the OpenLDAP
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>.
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.
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 ) )
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
35 * using nested groups (groups that are member of a group) is currently
36 * not supported, this may be added in a later release
39 /* the basic search filter for searches */
40 static struct berval group_filter = BER_BVC("(objectClass=posixGroup)");
42 /* the attributes to request with searches */
43 static struct berval group_keys[] = {
45 BER_BVC("userPassword"),
48 BER_BVC("uniqueMember"),
58 /* default values for attributes */
59 static struct berval default_group_userPassword = BER_BVC("*"); /* unmatchable */
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)
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 >
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,
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 )
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 );
98 Checks to see if the specified name is a valid group name.
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
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
109 static int isvalidgroupname(struct berval *name)
113 if ( !name->bv_val || !name->bv_len )
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]=='_' ) )
121 /* check other characters */
122 for (i=1;i<name->bv_len;i++)
124 #ifndef STRICT_GROUPS
125 /* allow spaces too */
126 if (name->bv_val[i] == ' ') continue;
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]=='-') )
134 /* no test failed so it must be good */
138 static int write_group(nssov_group_cbp *cbp,Entry *entry)
140 struct berval tmparr[2], tmpgid[2];
141 struct berval *names,*gids,*members;
142 struct berval passwd = {0};
144 int i,j,nummembers,rc;
146 /* get group name (cn) */
147 if (BER_BVISNULL(&cbp->name))
149 a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[CN_KEY].an_desc);
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);
162 BER_BVZERO(&names[1]);
164 /* get the group id(s) */
165 if (BER_BVISNULL(&cbp->gidnum))
167 a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[GID_KEY].an_desc);
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);
180 BER_BVZERO(&gids[1]);
182 /* get group passwd (userPassword) (use only first entry) */
183 a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[PWD_KEY].an_desc);
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) {
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);
199 members = cbp->op->o_tmpalloc( (i+1) * sizeof(struct berval), cbp->op->o_tmpmemctx );
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);
211 for (i=0; i<a->a_numvals; i++) {
212 if (nssov_dn2uid(cbp->op,cbp->ni,&a->a_nvals[i],&members[j]))
217 BER_BVZERO(&members[j]);
227 /* write entries for all names and gids */
228 for (i=0;!BER_BVISNULL(&names[i]);i++)
230 if (!isvalidgroupname(&names[i]))
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);
237 for (j=0;!BER_BVISNULL(&gids[j]);j++)
242 gid = strtol(gids[j].bv_val, &tmp, 0);
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,
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);
258 for (k=0;k<nummembers;k++) {
259 WRITE_BERVAL(cbp->fp,&members[k]);
265 /* free and return */
267 ber_bvarray_free_x( members, cbp->op->o_tmpmemctx );
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);
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)
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);
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)
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);
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)
335 struct berval filter;
336 /* no parameters to read */
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)