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