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