Please find attached version 0.2 of the uidnumber overlay I posted previously (http://www.openldap.org/lists/openldap-software/200806/msg00029.html).
This version does not search the directory every time a posixAccount add entry request comes in - only the first time such a request is made to the directory. Subsequent requests are processed via the cached next uidNumber overlay data. This version of the overlay tracks the next uidNumber per database (the previous version used a static, overlay scoped variable).
Just posting in case anyone ever finds it of use for their environment.
jr
joel reed wrote:
Please find attached version 0.2 of the uidnumber overlay I posted previously (http://www.openldap.org/lists/openldap-software/200806/msg00029.html).
Darn it! Forgot to include the file!
jr
/** * uidnumber.c * * Copyright (C) 2008 Joel W. Reed * 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 file LICENSE in the * top-level directory of the distribution or, alternatively, at * http://www.OpenLDAP.org/license.html. * * SEE LICENSE FOR MORE INFORMATION * * Author: Joel W. Reed * Email: joelwreed@gmail.com * Version: 0.2 * Updated: 06.29.2008 * * uidnumber * * This is an OpenLDAP overlay that intercepts ADD requests for posixAccount type * entries that do not have a uidNumber. When such ADD requests are found, * the overlay adds a uidNumber attribute with the next available uidNumber. */
#include "portable.h" #include "slap.h" #include "config.h"
static int uidnumber_search_cb( Operation *op, SlapReply *rs ); static unsigned long uidnumber_next_available( Operation *op );
static slap_overinst uidnumber; static ObjectClass *oc_posix_account; static char *uid_attr_name = "uidNumber";
typedef struct uidnumber_data { ldap_pvt_thread_mutex_t mutex; unsigned long max_uid_number; } uidnumber_data;
/** * The meat of the overlay. Look for posixAccount adds with no uidNumber, and * add in the next available uidNumber as needed. */ static int uidnumber_add( Operation *op, SlapReply *rs ) { Entry* to_add = NULL; AttributeDescription* ad = NULL; Attribute* attr = NULL; char uidstr[64]; struct berval uidbv = BER_BVNULL; unsigned long uid; const char* text; int rc;
to_add = op->oq_add.rs_e;
/* if the user doesn't have access, fall through to the normal ADD */ if(!access_allowed( op, to_add, slap_schema.si_ad_entry, NULL, ACL_WRITE, NULL )) { return SLAP_CB_CONTINUE; } /* we only care object posixAccount entries */ if(!is_entry_objectclass( (to_add), oc_posix_account, 0) ) { Debug(LDAP_DEBUG_TRACE, "%s: entry %s is not objectclass posixAccount\n", uidnumber.on_bi.bi_type, to_add->e_nname.bv_val, 0); return SLAP_CB_CONTINUE; }
/* if already has a uidNumber, no further processing required */ for ( attr = to_add->e_attrs; attr; attr = attr->a_next ) { if (!strcmp( attr->a_desc->ad_cname.bv_val, uid_attr_name )) { Debug(LDAP_DEBUG_TRACE, "%s: entry %s already has a uidNumber\n", uidnumber.on_bi.bi_type, to_add->e_nname.bv_val, 0); return SLAP_CB_CONTINUE; } }
uid = uidnumber_next_available(op);
rc = slap_str2ad( uid_attr_name, &ad, &text ); if(rc != LDAP_SUCCESS) { Debug( LDAP_DEBUG_ANY, "%s: failed to add uidNumber attribute to entry\n", uidnumber.on_bi.bi_type, 0, 0 ); return SLAP_CB_CONTINUE; }
sprintf( uidstr, "%lu", uid ); ber_str2bv( uidstr, 0, 0, &uidbv ); attr_merge_one( to_add, ad, &uidbv, 0 );
Debug( LDAP_DEBUG_ANY, "%s: added uidNumber %s to entry\n", uidnumber.on_bi.bi_type, uidstr, 0 );
return SLAP_CB_CONTINUE; }
static unsigned long uidnumber_next_available(Operation *op) { slap_overinst* on = (slap_overinst *)op->o_bd->bd_info; uidnumber_data* ad = on->on_bi.bi_private;
Operation nop = *op; SlapReply nrs = { REP_RESULT }; Filter* filter = NULL; slap_callback cb = { NULL, uidnumber_search_cb, NULL, ad }; struct berval fstr = BER_BVNULL; struct berval rootstr = BER_BVNULL; int rc;
/* if we already know the max uid, don't bother searching the tree */ if(ad->max_uid_number == 0) {
nop.o_callback = &cb; op->o_bd->bd_info = (BackendInfo *) on->on_info; nop.o_tag = LDAP_REQ_SEARCH; nop.o_ctrls = NULL; filter = str2filter( "(uidNumber=*)" ); filter2bv( filter, &fstr );
nop.ors_scope = LDAP_SCOPE_SUBTREE; nop.ors_deref = LDAP_DEREF_NEVER; nop.ors_slimit = -1;//SLAP_NO_LIMIT; nop.ors_tlimit = -1;//SLAP_NO_LIMIT; nop.ors_attrsonly = 1; nop.ors_attrs = slap_anlist_no_attrs; nop.ors_filter = filter; nop.ors_filterstr = fstr;
memset( &nrs, 0, sizeof(nrs) ); nrs.sr_type = REP_RESULT; nrs.sr_err = LDAP_SUCCESS; nrs.sr_entry = NULL; nrs.sr_flags |= REP_ENTRY_MUSTBEFREED; nrs.sr_text = NULL;
nop.o_req_dn = rootstr; nop.o_req_ndn = rootstr;
if(nop.o_bd->be_search) { rc = nop.o_bd->be_search( &nop, &nrs ); Debug( LDAP_DEBUG_TRACE, "%s: searched for entries with uidNumber attribute\n", uidnumber.on_bi.bi_type,0,0 ); } else { Debug( LDAP_DEBUG_ANY, "%s: backend missing search function\n", uidnumber.on_bi.bi_type,0,0 ); }
if(filter) filter_free( filter ); if(fstr.bv_val) ch_free( fstr.bv_val ); }
return ++(ad->max_uid_number); }
static int uidnumber_search_cb( Operation *op, SlapReply *rs ) { uidnumber_data* ad = op->o_callback->sc_private; Entry *entry = NULL;
if( rs->sr_type != REP_SEARCH ) return 0; if( rs->sr_entry ) { Debug( LDAP_DEBUG_TRACE, "%s: dn found: %s\n", uidnumber.on_bi.bi_type, rs->sr_entry->e_nname.bv_val, 0 );
entry = rs->sr_entry;
Attribute *attr = NULL; for (attr = entry->e_attrs; attr; attr = attr->a_next) { if(!strcmp( attr->a_desc->ad_cname.bv_val, uid_attr_name )) { if(attr->a_numvals > 0 ) { unsigned long tmp = strtoul( attr->a_vals[0].bv_val, 0, 0 ); Debug( LDAP_DEBUG_ANY, "%s: uidNumber found: %lu\n", uidnumber.on_bi.bi_type, tmp, 0 ); if( tmp >= ad->max_uid_number ) ad->max_uid_number = tmp; } } } }
return 0; }
static int uidnumber_db_init(BackendDB *be, ConfigReply *cr) { slap_overinst *on = (slap_overinst *)be->bd_info; uidnumber_data *ad = ch_calloc(1, sizeof(uidnumber_data));
on->on_bi.bi_private = ad; ldap_pvt_thread_mutex_init( &ad->mutex ); ad->max_uid_number = 0;
return 0; }
static int uidnumber_db_destroy(BackendDB *be, ConfigReply *cr) { slap_overinst *on = (slap_overinst *)be->bd_info; uidnumber_data *ad = on->on_bi.bi_private;
ldap_pvt_thread_mutex_destroy( &ad->mutex ); free( ad );
return 0; }
int uidnumber_init() { uidnumber.on_bi.bi_type = "uidnumber"; uidnumber.on_bi.bi_op_add = uidnumber_add; uidnumber.on_bi.bi_db_init = uidnumber_db_init; uidnumber.on_bi.bi_db_destroy = uidnumber_db_destroy;
oc_posix_account = oc_find( "posixAccount" ); if(oc_posix_account == NULL) { Debug( LDAP_DEBUG_ANY, "%s: unable to find default ObjectClass "posixAccount".\n", uidnumber.on_bi.bi_type, 0, 0 ); return -1; }
return ( overlay_register(&uidnumber) ); }
int init_module( int argc, char *argv[] ) { return uidnumber_init(); }
openldap-software@openldap.org