/* group.c - group lookup routines */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * 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 * . */ /* 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 /* ( 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;ibv_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; ia_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; ia_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;kfp,&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) )