mirror of
https://git.openldap.org/openldap/openldap.git
synced 2024-12-27 03:20:22 +08:00
347 lines
9.6 KiB
C
347 lines
9.6 KiB
C
/* group.c - group lookup routines */
|
|
/* $OpenLDAP$ */
|
|
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
|
*
|
|
* Copyright 2008-2021 The OpenLDAP Foundation.
|
|
* Portions Copyright 2008-2009 by Howard Chu, Symas Corp.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted only as authorized by the OpenLDAP
|
|
* Public License.
|
|
*
|
|
* A copy of this license is available in the file LICENSE in the
|
|
* top-level directory of the distribution or, alternatively, at
|
|
* <http://www.OpenLDAP.org/license.html>.
|
|
*/
|
|
/* ACKNOWLEDGEMENTS:
|
|
* This code references portions of the nss-ldapd package
|
|
* written by Arthur de Jong. The nss-ldapd code was forked
|
|
* from the nss-ldap library written by Luke Howard.
|
|
*/
|
|
|
|
#include "nssov.h"
|
|
|
|
/* for gid_t */
|
|
#include <grp.h>
|
|
|
|
/* ( nisSchema.2.2 NAME 'posixGroup' SUP top STRUCTURAL
|
|
* DESC 'Abstraction of a group of accounts'
|
|
* MUST ( cn $ gidNumber )
|
|
* MAY ( userPassword $ memberUid $ description ) )
|
|
*
|
|
* apart from that the above the uniqueMember attributes may be
|
|
* supported in a coming release (they map to DNs, which is an extra
|
|
* lookup step)
|
|
*
|
|
* using nested groups (groups that are member of a group) is currently
|
|
* not supported, this may be added in a later release
|
|
*/
|
|
|
|
/* the basic search filter for searches */
|
|
static struct berval group_filter = BER_BVC("(objectClass=posixGroup)");
|
|
|
|
/* the attributes to request with searches */
|
|
static struct berval group_keys[] = {
|
|
BER_BVC("cn"),
|
|
BER_BVC("userPassword"),
|
|
BER_BVC("gidNumber"),
|
|
BER_BVC("memberUid"),
|
|
BER_BVC("uniqueMember"),
|
|
BER_BVNULL
|
|
};
|
|
|
|
#define CN_KEY 0
|
|
#define PWD_KEY 1
|
|
#define GID_KEY 2
|
|
#define UID_KEY 3
|
|
#define MEM_KEY 4
|
|
|
|
/* default values for attributes */
|
|
static struct berval default_group_userPassword = BER_BVC("*"); /* unmatchable */
|
|
|
|
NSSOV_CBPRIV(group,
|
|
nssov_info *ni;
|
|
char buf[256];
|
|
struct berval name;
|
|
struct berval gidnum;
|
|
struct berval user;
|
|
int wantmembers;);
|
|
|
|
/* create a search filter for searching a group entry
|
|
by member uid, return -1 on errors */
|
|
static int mkfilter_group_bymember(nssov_group_cbp *cbp,struct berval *buf)
|
|
{
|
|
struct berval dn;
|
|
/* try to translate uid to DN */
|
|
nssov_uid2dn(cbp->op,cbp->ni,&cbp->user,&dn);
|
|
if (BER_BVISNULL(&dn)) {
|
|
if (cbp->user.bv_len + cbp->mi->mi_filter.bv_len + cbp->mi->mi_attrs[UID_KEY].an_desc->ad_cname.bv_len + 6 >
|
|
buf->bv_len )
|
|
return -1;
|
|
buf->bv_len = snprintf(buf->bv_val, buf->bv_len, "(&%s(%s=%s))",
|
|
cbp->mi->mi_filter.bv_val, cbp->mi->mi_attrs[UID_KEY].an_desc->ad_cname.bv_val,
|
|
cbp->user.bv_val );
|
|
} else { /* also lookup using user DN */
|
|
if (cbp->user.bv_len + cbp->mi->mi_filter.bv_len + cbp->mi->mi_attrs[UID_KEY].an_desc->ad_cname.bv_len +
|
|
dn.bv_len + cbp->mi->mi_attrs[MEM_KEY].an_desc->ad_cname.bv_len + 12 > buf->bv_len )
|
|
return -1;
|
|
buf->bv_len = snprintf(buf->bv_val, buf->bv_len, "(&%s(|(%s=%s)(%s=%s)))",
|
|
cbp->mi->mi_filter.bv_val,
|
|
cbp->mi->mi_attrs[UID_KEY].an_desc->ad_cname.bv_val, cbp->user.bv_val,
|
|
cbp->mi->mi_attrs[MEM_KEY].an_desc->ad_cname.bv_val, dn.bv_val );
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
NSSOV_INIT(group)
|
|
|
|
/*
|
|
Checks to see if the specified name is a valid group name.
|
|
|
|
This test is based on the definition from POSIX (IEEE Std 1003.1, 2004,
|
|
3.189 Group Name and 3.276 Portable Filename Character Set):
|
|
http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap03.html#tag_03_189
|
|
http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap03.html#tag_03_276
|
|
|
|
The standard defines group names valid if they only contain characters from
|
|
the set [A-Za-z0-9._-] where the hyphen should not be used as first
|
|
character.
|
|
*/
|
|
static int isvalidgroupname(struct berval *name)
|
|
{
|
|
int i;
|
|
|
|
if ( !name->bv_val || !name->bv_len )
|
|
return 0;
|
|
/* check first character */
|
|
if ( ! ( (name->bv_val[0]>='A' && name->bv_val[0] <= 'Z') ||
|
|
(name->bv_val[0]>='a' && name->bv_val[0] <= 'z') ||
|
|
(name->bv_val[0]>='0' && name->bv_val[0] <= '9') ||
|
|
name->bv_val[0]=='.' || name->bv_val[0]=='_' ) )
|
|
return 0;
|
|
/* check other characters */
|
|
for (i=1;i<name->bv_len;i++)
|
|
{
|
|
#ifndef STRICT_GROUPS
|
|
/* allow spaces too */
|
|
if (name->bv_val[i] == ' ') continue;
|
|
#endif
|
|
if ( ! ( (name->bv_val[i]>='A' && name->bv_val[i] <= 'Z') ||
|
|
(name->bv_val[i]>='a' && name->bv_val[i] <= 'z') ||
|
|
(name->bv_val[i]>='0' && name->bv_val[i] <= '9') ||
|
|
name->bv_val[i]=='.' || name->bv_val[i]=='_' || name->bv_val[i]=='-') )
|
|
return 0;
|
|
}
|
|
/* no test failed so it must be good */
|
|
return -1;
|
|
}
|
|
|
|
static int write_group(nssov_group_cbp *cbp,Entry *entry)
|
|
{
|
|
struct berval tmparr[2], tmpgid[2];
|
|
struct berval *names,*gids,*members;
|
|
struct berval passwd = {0};
|
|
Attribute *a;
|
|
int i,j,nummembers,rc = 0;
|
|
|
|
/* get group name (cn) */
|
|
if (BER_BVISNULL(&cbp->name))
|
|
{
|
|
a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[CN_KEY].an_desc);
|
|
if ( !a )
|
|
{
|
|
Debug(LDAP_DEBUG_ANY,"group entry %s does not contain %s value\n",
|
|
entry->e_name.bv_val, cbp->mi->mi_attrs[CN_KEY].an_desc->ad_cname.bv_val );
|
|
return 0;
|
|
}
|
|
names = a->a_vals;
|
|
}
|
|
else
|
|
{
|
|
names=tmparr;
|
|
names[0]=cbp->name;
|
|
BER_BVZERO(&names[1]);
|
|
}
|
|
/* get the group id(s) */
|
|
if (BER_BVISNULL(&cbp->gidnum))
|
|
{
|
|
a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[GID_KEY].an_desc);
|
|
if ( !a )
|
|
{
|
|
Debug(LDAP_DEBUG_ANY,"group entry %s does not contain %s value\n",
|
|
entry->e_name.bv_val, cbp->mi->mi_attrs[GID_KEY].an_desc->ad_cname.bv_val );
|
|
return 0;
|
|
}
|
|
gids = a->a_vals;
|
|
}
|
|
else
|
|
{
|
|
gids=tmpgid;
|
|
gids[0]=cbp->gidnum;
|
|
BER_BVZERO(&gids[1]);
|
|
}
|
|
/* get group passwd (userPassword) (use only first entry) */
|
|
a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[PWD_KEY].an_desc);
|
|
if (a)
|
|
get_userpassword(&a->a_vals[0], &passwd);
|
|
if (BER_BVISNULL(&passwd))
|
|
passwd=default_group_userPassword;
|
|
/* get group members (memberUid&uniqueMember) */
|
|
if (cbp->wantmembers) {
|
|
Attribute *b;
|
|
i = 0; j = 0;
|
|
a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[UID_KEY].an_desc);
|
|
b = attr_find(entry->e_attrs, cbp->mi->mi_attrs[MEM_KEY].an_desc);
|
|
if ( a )
|
|
i += a->a_numvals;
|
|
if ( b )
|
|
i += b->a_numvals;
|
|
if ( i ) {
|
|
members = cbp->op->o_tmpalloc( (i+1) * sizeof(struct berval), cbp->op->o_tmpmemctx );
|
|
|
|
if ( a ) {
|
|
for (i=0; i<a->a_numvals; i++) {
|
|
if (isvalidusername(&a->a_vals[i])) {
|
|
ber_dupbv_x(&members[j],&a->a_vals[i],cbp->op->o_tmpmemctx);
|
|
j++;
|
|
}
|
|
}
|
|
}
|
|
a = b;
|
|
if ( a ) {
|
|
for (i=0; i<a->a_numvals; i++) {
|
|
if (nssov_dn2uid(cbp->op,cbp->ni,&a->a_nvals[i],&members[j]))
|
|
j++;
|
|
}
|
|
}
|
|
nummembers = j;
|
|
BER_BVZERO(&members[j]);
|
|
} else {
|
|
members=NULL;
|
|
nummembers = 0;
|
|
}
|
|
|
|
} else {
|
|
members=NULL;
|
|
nummembers = 0;
|
|
}
|
|
/* write entries for all names and gids */
|
|
for (i=0;!BER_BVISNULL(&names[i]);i++)
|
|
{
|
|
if (!isvalidgroupname(&names[i]))
|
|
{
|
|
Debug(LDAP_DEBUG_ANY,"nssov: group entry %s contains invalid group name: \"%s\"\n",
|
|
entry->e_name.bv_val,names[i].bv_val );
|
|
}
|
|
else
|
|
{
|
|
for (j=0;!BER_BVISNULL(&gids[j]);j++)
|
|
{
|
|
char *tmp;
|
|
int tmpint32;
|
|
gid_t gid;
|
|
gid = strtol(gids[j].bv_val, &tmp, 0);
|
|
if ( *tmp ) {
|
|
Debug(LDAP_DEBUG_ANY,"nssov: group entry %s contains non-numeric %s value: \"%s\"\n",
|
|
entry->e_name.bv_val, cbp->mi->mi_attrs[GID_KEY].an_desc->ad_cname.bv_val,
|
|
names[i].bv_val);
|
|
continue;
|
|
}
|
|
WRITE_INT32(cbp->fp,NSLCD_RESULT_BEGIN);
|
|
WRITE_BERVAL(cbp->fp,&names[i]);
|
|
WRITE_BERVAL(cbp->fp,&passwd);
|
|
WRITE_INT32(cbp->fp,gid);
|
|
/* write a list of values */
|
|
WRITE_INT32(cbp->fp,nummembers);
|
|
if (nummembers)
|
|
{
|
|
int k;
|
|
for (k=0;k<nummembers;k++) {
|
|
WRITE_BERVAL(cbp->fp,&members[k]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/* free and return */
|
|
if (members!=NULL)
|
|
ber_bvarray_free_x( members, cbp->op->o_tmpmemctx );
|
|
return rc;
|
|
}
|
|
|
|
NSSOV_CB(group)
|
|
|
|
NSSOV_HANDLE(
|
|
group,byname,
|
|
char fbuf[1024];
|
|
struct berval filter = {sizeof(fbuf)};
|
|
filter.bv_val = fbuf;
|
|
READ_STRING(fp,cbp.buf);
|
|
cbp.name.bv_len = tmpint32;
|
|
cbp.name.bv_val = cbp.buf;
|
|
if (!isvalidgroupname(&cbp.name)) {
|
|
Debug(LDAP_DEBUG_ANY,"nssov_group_byname(%s): invalid group name\n",cbp.name.bv_val);
|
|
return -1;
|
|
}
|
|
cbp.wantmembers = 1;
|
|
cbp.ni = ni;
|
|
BER_BVZERO(&cbp.gidnum);
|
|
BER_BVZERO(&cbp.user);,
|
|
Debug(LDAP_DEBUG_TRACE,"nslcd_group_byname(%s)\n",cbp.name.bv_val);,
|
|
NSLCD_ACTION_GROUP_BYNAME,
|
|
nssov_filter_byname(cbp.mi,CN_KEY,&cbp.name,&filter)
|
|
)
|
|
|
|
NSSOV_HANDLE(
|
|
group,bygid,
|
|
gid_t gid;
|
|
char fbuf[1024];
|
|
struct berval filter = {sizeof(fbuf)};
|
|
filter.bv_val = fbuf;
|
|
READ_INT32(fp,gid);
|
|
cbp.gidnum.bv_val = cbp.buf;
|
|
cbp.gidnum.bv_len = snprintf(cbp.buf,sizeof(cbp.buf),"%d",gid);
|
|
cbp.wantmembers = 1;
|
|
cbp.ni = ni;
|
|
BER_BVZERO(&cbp.name);
|
|
BER_BVZERO(&cbp.user);,
|
|
Debug(LDAP_DEBUG_TRACE,"nssov_group_bygid(%s)\n",cbp.gidnum.bv_val);,
|
|
NSLCD_ACTION_GROUP_BYGID,
|
|
nssov_filter_byid(cbp.mi,GID_KEY,&cbp.gidnum,&filter)
|
|
)
|
|
|
|
NSSOV_HANDLE(
|
|
group,bymember,
|
|
char fbuf[1024];
|
|
struct berval filter = {sizeof(fbuf)};
|
|
filter.bv_val = fbuf;
|
|
READ_STRING(fp,cbp.buf);
|
|
cbp.user.bv_len = tmpint32;
|
|
cbp.user.bv_val = cbp.buf;
|
|
if (!isvalidusername(&cbp.user)) {
|
|
Debug(LDAP_DEBUG_ANY,"nssov_group_bymember(%s): invalid user name\n",cbp.user.bv_val);
|
|
return -1;
|
|
}
|
|
cbp.wantmembers = 0;
|
|
cbp.ni = ni;
|
|
BER_BVZERO(&cbp.name);
|
|
BER_BVZERO(&cbp.gidnum);,
|
|
Debug(LDAP_DEBUG_TRACE,"nssov_group_bymember(%s)\n",cbp.user.bv_val);,
|
|
NSLCD_ACTION_GROUP_BYMEMBER,
|
|
mkfilter_group_bymember(&cbp,&filter)
|
|
)
|
|
|
|
NSSOV_HANDLE(
|
|
group,all,
|
|
struct berval filter;
|
|
/* no parameters to read */
|
|
cbp.wantmembers = 1;
|
|
cbp.ni = ni;
|
|
BER_BVZERO(&cbp.name);
|
|
BER_BVZERO(&cbp.gidnum);,
|
|
Debug(LDAP_DEBUG_TRACE,"nssov_group_all()\n");,
|
|
NSLCD_ACTION_GROUP_ALL,
|
|
(filter=cbp.mi->mi_filter,0)
|
|
)
|