Home | History | Annotate | Line # | Download | only in nssov
      1  1.3  christos /*	$NetBSD: group.c,v 1.4 2025/09/05 21:16:17 christos Exp $	*/
      2  1.2  christos 
      3  1.1     lukem /* group.c - group lookup routines */
      4  1.2  christos /* $OpenLDAP$ */
      5  1.2  christos /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
      6  1.2  christos  *
      7  1.4  christos  * Copyright 2008-2024 The OpenLDAP Foundation.
      8  1.2  christos  * Portions Copyright 2008-2009 by Howard Chu, Symas Corp.
      9  1.1     lukem  * All rights reserved.
     10  1.1     lukem  *
     11  1.1     lukem  * Redistribution and use in source and binary forms, with or without
     12  1.1     lukem  * modification, are permitted only as authorized by the OpenLDAP
     13  1.1     lukem  * Public License.
     14  1.1     lukem  *
     15  1.1     lukem  * A copy of this license is available in the file LICENSE in the
     16  1.1     lukem  * top-level directory of the distribution or, alternatively, at
     17  1.1     lukem  * <http://www.OpenLDAP.org/license.html>.
     18  1.1     lukem  */
     19  1.2  christos /* ACKNOWLEDGEMENTS:
     20  1.1     lukem  * This code references portions of the nss-ldapd package
     21  1.1     lukem  * written by Arthur de Jong. The nss-ldapd code was forked
     22  1.1     lukem  * from the nss-ldap library written by Luke Howard.
     23  1.1     lukem  */
     24  1.1     lukem 
     25  1.1     lukem #include "nssov.h"
     26  1.1     lukem 
     27  1.1     lukem /* for gid_t */
     28  1.1     lukem #include <grp.h>
     29  1.1     lukem 
     30  1.1     lukem /* ( nisSchema.2.2 NAME 'posixGroup' SUP top STRUCTURAL
     31  1.1     lukem  *   DESC 'Abstraction of a group of accounts'
     32  1.1     lukem  *   MUST ( cn $ gidNumber )
     33  1.1     lukem  *   MAY ( userPassword $ memberUid $ description ) )
     34  1.1     lukem  *
     35  1.1     lukem  * apart from that the above the uniqueMember attributes may be
     36  1.1     lukem  * supported in a coming release (they map to DNs, which is an extra
     37  1.1     lukem  * lookup step)
     38  1.1     lukem  *
     39  1.1     lukem  * using nested groups (groups that are member of a group) is currently
     40  1.1     lukem  * not supported, this may be added in a later release
     41  1.1     lukem  */
     42  1.1     lukem 
     43  1.1     lukem /* the basic search filter for searches */
     44  1.1     lukem static struct berval group_filter = BER_BVC("(objectClass=posixGroup)");
     45  1.1     lukem 
     46  1.1     lukem /* the attributes to request with searches */
     47  1.1     lukem static struct berval group_keys[] = {
     48  1.1     lukem 	BER_BVC("cn"),
     49  1.1     lukem 	BER_BVC("userPassword"),
     50  1.1     lukem 	BER_BVC("gidNumber"),
     51  1.1     lukem 	BER_BVC("memberUid"),
     52  1.1     lukem 	BER_BVC("uniqueMember"),
     53  1.1     lukem 	BER_BVNULL
     54  1.1     lukem };
     55  1.1     lukem 
     56  1.1     lukem #define	CN_KEY	0
     57  1.1     lukem #define	PWD_KEY	1
     58  1.1     lukem #define	GID_KEY	2
     59  1.1     lukem #define	UID_KEY	3
     60  1.1     lukem #define	MEM_KEY	4
     61  1.1     lukem 
     62  1.1     lukem /* default values for attributes */
     63  1.1     lukem static struct berval default_group_userPassword     = BER_BVC("*"); /* unmatchable */
     64  1.1     lukem 
     65  1.1     lukem NSSOV_CBPRIV(group,
     66  1.1     lukem 	nssov_info *ni;
     67  1.1     lukem 	char buf[256];
     68  1.1     lukem 	struct berval name;
     69  1.1     lukem 	struct berval gidnum;
     70  1.1     lukem 	struct berval user;
     71  1.1     lukem 	int wantmembers;);
     72  1.1     lukem 
     73  1.1     lukem /* create a search filter for searching a group entry
     74  1.1     lukem 	 by member uid, return -1 on errors */
     75  1.1     lukem static int mkfilter_group_bymember(nssov_group_cbp *cbp,struct berval *buf)
     76  1.1     lukem {
     77  1.1     lukem 	struct berval dn;
     78  1.1     lukem 	/* try to translate uid to DN */
     79  1.1     lukem 	nssov_uid2dn(cbp->op,cbp->ni,&cbp->user,&dn);
     80  1.1     lukem 	if (BER_BVISNULL(&dn)) {
     81  1.1     lukem 		if (cbp->user.bv_len + cbp->mi->mi_filter.bv_len + cbp->mi->mi_attrs[UID_KEY].an_desc->ad_cname.bv_len + 6 >
     82  1.1     lukem 			buf->bv_len )
     83  1.1     lukem 			return -1;
     84  1.1     lukem 		buf->bv_len = snprintf(buf->bv_val, buf->bv_len, "(&%s(%s=%s))",
     85  1.1     lukem 			cbp->mi->mi_filter.bv_val, cbp->mi->mi_attrs[UID_KEY].an_desc->ad_cname.bv_val,
     86  1.1     lukem 			cbp->user.bv_val );
     87  1.1     lukem 	} else { /* also lookup using user DN */
     88  1.1     lukem 		if (cbp->user.bv_len + cbp->mi->mi_filter.bv_len + cbp->mi->mi_attrs[UID_KEY].an_desc->ad_cname.bv_len +
     89  1.1     lukem 			dn.bv_len + cbp->mi->mi_attrs[MEM_KEY].an_desc->ad_cname.bv_len + 12 > buf->bv_len )
     90  1.1     lukem 			return -1;
     91  1.1     lukem 		buf->bv_len = snprintf(buf->bv_val, buf->bv_len, "(&%s(|(%s=%s)(%s=%s)))",
     92  1.1     lukem 			cbp->mi->mi_filter.bv_val,
     93  1.1     lukem 			cbp->mi->mi_attrs[UID_KEY].an_desc->ad_cname.bv_val, cbp->user.bv_val,
     94  1.1     lukem 			cbp->mi->mi_attrs[MEM_KEY].an_desc->ad_cname.bv_val, dn.bv_val );
     95  1.1     lukem 	}
     96  1.1     lukem 	return 0;
     97  1.1     lukem }
     98  1.1     lukem 
     99  1.1     lukem NSSOV_INIT(group)
    100  1.1     lukem 
    101  1.1     lukem /*
    102  1.1     lukem 	 Checks to see if the specified name is a valid group name.
    103  1.1     lukem 
    104  1.1     lukem 	 This test is based on the definition from POSIX (IEEE Std 1003.1, 2004,
    105  1.1     lukem 	 3.189 Group Name and 3.276 Portable Filename Character Set):
    106  1.1     lukem 	 http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap03.html#tag_03_189
    107  1.1     lukem 	 http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap03.html#tag_03_276
    108  1.1     lukem 
    109  1.1     lukem 	 The standard defines group names valid if they only contain characters from
    110  1.1     lukem 	 the set [A-Za-z0-9._-] where the hyphen should not be used as first
    111  1.1     lukem 	 character.
    112  1.1     lukem */
    113  1.1     lukem static int isvalidgroupname(struct berval *name)
    114  1.1     lukem {
    115  1.1     lukem 	int i;
    116  1.1     lukem 
    117  1.1     lukem 	if ( !name->bv_val || !name->bv_len )
    118  1.1     lukem 		return 0;
    119  1.1     lukem 	/* check first character */
    120  1.1     lukem 	if ( ! ( (name->bv_val[0]>='A' && name->bv_val[0] <= 'Z') ||
    121  1.1     lukem 					 (name->bv_val[0]>='a' && name->bv_val[0] <= 'z') ||
    122  1.1     lukem 					 (name->bv_val[0]>='0' && name->bv_val[0] <= '9') ||
    123  1.1     lukem 					 name->bv_val[0]=='.' || name->bv_val[0]=='_' ) )
    124  1.1     lukem 		return 0;
    125  1.1     lukem 	/* check other characters */
    126  1.1     lukem 	for (i=1;i<name->bv_len;i++)
    127  1.1     lukem 	{
    128  1.2  christos #ifndef STRICT_GROUPS
    129  1.2  christos 		/* allow spaces too */
    130  1.2  christos 		if (name->bv_val[i] == ' ') continue;
    131  1.2  christos #endif
    132  1.1     lukem 		if ( ! ( (name->bv_val[i]>='A' && name->bv_val[i] <= 'Z') ||
    133  1.1     lukem 						 (name->bv_val[i]>='a' && name->bv_val[i] <= 'z') ||
    134  1.1     lukem 						 (name->bv_val[i]>='0' && name->bv_val[i] <= '9') ||
    135  1.1     lukem 						 name->bv_val[i]=='.' || name->bv_val[i]=='_' || name->bv_val[i]=='-') )
    136  1.1     lukem 			return 0;
    137  1.1     lukem 	}
    138  1.1     lukem 	/* no test failed so it must be good */
    139  1.1     lukem 	return -1;
    140  1.1     lukem }
    141  1.1     lukem 
    142  1.1     lukem static int write_group(nssov_group_cbp *cbp,Entry *entry)
    143  1.1     lukem {
    144  1.1     lukem 	struct berval tmparr[2], tmpgid[2];
    145  1.1     lukem 	struct berval *names,*gids,*members;
    146  1.1     lukem 	struct berval passwd = {0};
    147  1.1     lukem 	Attribute *a;
    148  1.2  christos 	int i,j,nummembers,rc = 0;
    149  1.1     lukem 
    150  1.1     lukem 	/* get group name (cn) */
    151  1.1     lukem 	if (BER_BVISNULL(&cbp->name))
    152  1.1     lukem 	{
    153  1.1     lukem 		a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[CN_KEY].an_desc);
    154  1.1     lukem 		if ( !a )
    155  1.1     lukem 		{
    156  1.2  christos 			Debug(LDAP_DEBUG_ANY,"group entry %s does not contain %s value\n",
    157  1.3  christos 					entry->e_name.bv_val, cbp->mi->mi_attrs[CN_KEY].an_desc->ad_cname.bv_val );
    158  1.1     lukem 			return 0;
    159  1.1     lukem 		}
    160  1.1     lukem 		names = a->a_vals;
    161  1.1     lukem 	}
    162  1.1     lukem 	else
    163  1.1     lukem 	{
    164  1.1     lukem 		names=tmparr;
    165  1.1     lukem 		names[0]=cbp->name;
    166  1.1     lukem 		BER_BVZERO(&names[1]);
    167  1.1     lukem 	}
    168  1.1     lukem 	/* get the group id(s) */
    169  1.1     lukem 	if (BER_BVISNULL(&cbp->gidnum))
    170  1.1     lukem 	{
    171  1.1     lukem 		a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[GID_KEY].an_desc);
    172  1.1     lukem 		if ( !a )
    173  1.1     lukem 		{
    174  1.2  christos 			Debug(LDAP_DEBUG_ANY,"group entry %s does not contain %s value\n",
    175  1.3  christos 					entry->e_name.bv_val, cbp->mi->mi_attrs[GID_KEY].an_desc->ad_cname.bv_val );
    176  1.1     lukem 			return 0;
    177  1.1     lukem 		}
    178  1.1     lukem 		gids = a->a_vals;
    179  1.1     lukem 	}
    180  1.1     lukem 	else
    181  1.1     lukem 	{
    182  1.1     lukem 		gids=tmpgid;
    183  1.1     lukem 		gids[0]=cbp->gidnum;
    184  1.1     lukem 		BER_BVZERO(&gids[1]);
    185  1.1     lukem 	}
    186  1.1     lukem 	/* get group passwd (userPassword) (use only first entry) */
    187  1.1     lukem 	a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[PWD_KEY].an_desc);
    188  1.1     lukem 	if (a)
    189  1.1     lukem 		get_userpassword(&a->a_vals[0], &passwd);
    190  1.1     lukem 	if (BER_BVISNULL(&passwd))
    191  1.1     lukem 		passwd=default_group_userPassword;
    192  1.1     lukem 	/* get group members (memberUid&uniqueMember) */
    193  1.1     lukem 	if (cbp->wantmembers) {
    194  1.1     lukem 		Attribute *b;
    195  1.1     lukem 		i = 0; j = 0;
    196  1.1     lukem 		a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[UID_KEY].an_desc);
    197  1.1     lukem 		b = attr_find(entry->e_attrs, cbp->mi->mi_attrs[MEM_KEY].an_desc);
    198  1.1     lukem 		if ( a )
    199  1.1     lukem 			i += a->a_numvals;
    200  1.1     lukem 		if ( b )
    201  1.1     lukem 			i += b->a_numvals;
    202  1.2  christos 		if ( i ) {
    203  1.1     lukem 			members = cbp->op->o_tmpalloc( (i+1) * sizeof(struct berval), cbp->op->o_tmpmemctx );
    204  1.1     lukem 
    205  1.2  christos 			if ( a ) {
    206  1.2  christos 				for (i=0; i<a->a_numvals; i++) {
    207  1.2  christos 					if (isvalidusername(&a->a_vals[i])) {
    208  1.2  christos 						ber_dupbv_x(&members[j],&a->a_vals[i],cbp->op->o_tmpmemctx);
    209  1.2  christos 						j++;
    210  1.2  christos 					}
    211  1.1     lukem 				}
    212  1.1     lukem 			}
    213  1.2  christos 			a = b;
    214  1.2  christos 			if ( a ) {
    215  1.2  christos 				for (i=0; i<a->a_numvals; i++) {
    216  1.2  christos 					if (nssov_dn2uid(cbp->op,cbp->ni,&a->a_nvals[i],&members[j]))
    217  1.2  christos 						j++;
    218  1.2  christos 				}
    219  1.1     lukem 			}
    220  1.2  christos 			nummembers = j;
    221  1.2  christos 			BER_BVZERO(&members[j]);
    222  1.2  christos 		} else {
    223  1.2  christos 			members=NULL;
    224  1.2  christos 			nummembers = 0;
    225  1.1     lukem 		}
    226  1.2  christos 
    227  1.1     lukem 	} else {
    228  1.1     lukem 		members=NULL;
    229  1.1     lukem 		nummembers = 0;
    230  1.1     lukem 	}
    231  1.1     lukem 	/* write entries for all names and gids */
    232  1.1     lukem 	for (i=0;!BER_BVISNULL(&names[i]);i++)
    233  1.1     lukem 	{
    234  1.1     lukem 		if (!isvalidgroupname(&names[i]))
    235  1.1     lukem 		{
    236  1.2  christos 			Debug(LDAP_DEBUG_ANY,"nssov: group entry %s contains invalid group name: \"%s\"\n",
    237  1.3  christos 													entry->e_name.bv_val,names[i].bv_val );
    238  1.1     lukem 		}
    239  1.1     lukem 		else
    240  1.1     lukem 		{
    241  1.1     lukem 			for (j=0;!BER_BVISNULL(&gids[j]);j++)
    242  1.1     lukem 			{
    243  1.1     lukem 				char *tmp;
    244  1.1     lukem 				int tmpint32;
    245  1.1     lukem 				gid_t gid;
    246  1.1     lukem 				gid = strtol(gids[j].bv_val, &tmp, 0);
    247  1.1     lukem 				if ( *tmp ) {
    248  1.2  christos 					Debug(LDAP_DEBUG_ANY,"nssov: group entry %s contains non-numeric %s value: \"%s\"\n",
    249  1.1     lukem 						entry->e_name.bv_val, cbp->mi->mi_attrs[GID_KEY].an_desc->ad_cname.bv_val,
    250  1.1     lukem 						names[i].bv_val);
    251  1.1     lukem 					continue;
    252  1.1     lukem 				}
    253  1.2  christos 				WRITE_INT32(cbp->fp,NSLCD_RESULT_BEGIN);
    254  1.1     lukem 				WRITE_BERVAL(cbp->fp,&names[i]);
    255  1.1     lukem 				WRITE_BERVAL(cbp->fp,&passwd);
    256  1.2  christos 				WRITE_INT32(cbp->fp,gid);
    257  1.1     lukem 				/* write a list of values */
    258  1.1     lukem 				WRITE_INT32(cbp->fp,nummembers);
    259  1.1     lukem 				if (nummembers)
    260  1.1     lukem 				{
    261  1.1     lukem 					int k;
    262  1.1     lukem 					for (k=0;k<nummembers;k++) {
    263  1.1     lukem 						WRITE_BERVAL(cbp->fp,&members[k]);
    264  1.1     lukem 					}
    265  1.1     lukem 				}
    266  1.1     lukem 			}
    267  1.1     lukem 		}
    268  1.1     lukem 	}
    269  1.1     lukem 	/* free and return */
    270  1.1     lukem 	if (members!=NULL)
    271  1.1     lukem 		ber_bvarray_free_x( members, cbp->op->o_tmpmemctx );
    272  1.1     lukem 	return rc;
    273  1.1     lukem }
    274  1.1     lukem 
    275  1.1     lukem NSSOV_CB(group)
    276  1.1     lukem 
    277  1.1     lukem NSSOV_HANDLE(
    278  1.1     lukem 	group,byname,
    279  1.1     lukem 	char fbuf[1024];
    280  1.1     lukem 	struct berval filter = {sizeof(fbuf)};
    281  1.1     lukem 	filter.bv_val = fbuf;
    282  1.2  christos 	READ_STRING(fp,cbp.buf);
    283  1.1     lukem 	cbp.name.bv_len = tmpint32;
    284  1.1     lukem 	cbp.name.bv_val = cbp.buf;
    285  1.1     lukem 	if (!isvalidgroupname(&cbp.name)) {
    286  1.3  christos 		Debug(LDAP_DEBUG_ANY,"nssov_group_byname(%s): invalid group name\n",cbp.name.bv_val);
    287  1.1     lukem 		return -1;
    288  1.1     lukem 	}
    289  1.1     lukem 	cbp.wantmembers = 1;
    290  1.1     lukem 	cbp.ni = ni;
    291  1.1     lukem 	BER_BVZERO(&cbp.gidnum);
    292  1.1     lukem 	BER_BVZERO(&cbp.user);,
    293  1.3  christos 	Debug(LDAP_DEBUG_TRACE,"nslcd_group_byname(%s)\n",cbp.name.bv_val);,
    294  1.1     lukem 	NSLCD_ACTION_GROUP_BYNAME,
    295  1.1     lukem 	nssov_filter_byname(cbp.mi,CN_KEY,&cbp.name,&filter)
    296  1.1     lukem )
    297  1.1     lukem 
    298  1.1     lukem NSSOV_HANDLE(
    299  1.1     lukem 	group,bygid,
    300  1.1     lukem 	gid_t gid;
    301  1.1     lukem 	char fbuf[1024];
    302  1.1     lukem 	struct berval filter = {sizeof(fbuf)};
    303  1.1     lukem 	filter.bv_val = fbuf;
    304  1.2  christos 	READ_INT32(fp,gid);
    305  1.1     lukem 	cbp.gidnum.bv_val = cbp.buf;
    306  1.1     lukem 	cbp.gidnum.bv_len = snprintf(cbp.buf,sizeof(cbp.buf),"%d",gid);
    307  1.1     lukem 	cbp.wantmembers = 1;
    308  1.1     lukem 	cbp.ni = ni;
    309  1.1     lukem 	BER_BVZERO(&cbp.name);
    310  1.1     lukem 	BER_BVZERO(&cbp.user);,
    311  1.3  christos 	Debug(LDAP_DEBUG_TRACE,"nssov_group_bygid(%s)\n",cbp.gidnum.bv_val);,
    312  1.1     lukem 	NSLCD_ACTION_GROUP_BYGID,
    313  1.1     lukem 	nssov_filter_byid(cbp.mi,GID_KEY,&cbp.gidnum,&filter)
    314  1.1     lukem )
    315  1.1     lukem 
    316  1.1     lukem NSSOV_HANDLE(
    317  1.1     lukem 	group,bymember,
    318  1.1     lukem 	char fbuf[1024];
    319  1.1     lukem 	struct berval filter = {sizeof(fbuf)};
    320  1.1     lukem 	filter.bv_val = fbuf;
    321  1.2  christos 	READ_STRING(fp,cbp.buf);
    322  1.1     lukem 	cbp.user.bv_len = tmpint32;
    323  1.1     lukem 	cbp.user.bv_val = cbp.buf;
    324  1.1     lukem 	if (!isvalidusername(&cbp.user)) {
    325  1.3  christos 		Debug(LDAP_DEBUG_ANY,"nssov_group_bymember(%s): invalid user name\n",cbp.user.bv_val);
    326  1.1     lukem 		return -1;
    327  1.1     lukem 	}
    328  1.1     lukem 	cbp.wantmembers = 0;
    329  1.1     lukem 	cbp.ni = ni;
    330  1.1     lukem 	BER_BVZERO(&cbp.name);
    331  1.1     lukem 	BER_BVZERO(&cbp.gidnum);,
    332  1.3  christos 	Debug(LDAP_DEBUG_TRACE,"nssov_group_bymember(%s)\n",cbp.user.bv_val);,
    333  1.1     lukem 	NSLCD_ACTION_GROUP_BYMEMBER,
    334  1.1     lukem 	mkfilter_group_bymember(&cbp,&filter)
    335  1.1     lukem )
    336  1.1     lukem 
    337  1.1     lukem NSSOV_HANDLE(
    338  1.1     lukem 	group,all,
    339  1.1     lukem 	struct berval filter;
    340  1.1     lukem 	/* no parameters to read */
    341  1.1     lukem 	cbp.wantmembers = 1;
    342  1.1     lukem 	cbp.ni = ni;
    343  1.1     lukem 	BER_BVZERO(&cbp.name);
    344  1.1     lukem 	BER_BVZERO(&cbp.gidnum);,
    345  1.3  christos 	Debug(LDAP_DEBUG_TRACE,"nssov_group_all()\n");,
    346  1.1     lukem 	NSLCD_ACTION_GROUP_ALL,
    347  1.1     lukem 	(filter=cbp.mi->mi_filter,0)
    348  1.1     lukem )
    349