[Date Prev][Date Next] [Chronological] [Thread] [Top]

Re: automatic uidnumber overlay version 0.2



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();
}