diff options
Diffstat (limited to '')
-rw-r--r-- | contrib/slapd-modules/nssov/group.c | 346 |
1 files changed, 346 insertions, 0 deletions
diff --git a/contrib/slapd-modules/nssov/group.c b/contrib/slapd-modules/nssov/group.c new file mode 100644 index 0000000..1d93451 --- /dev/null +++ b/contrib/slapd-modules/nssov/group.c @@ -0,0 +1,346 @@ +/* group.c - group lookup routines */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2008-2022 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) +) |