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

automatic uidnumber overlay



The attached uidnumber.c overlay intercepts ADD requests for entries with a posixAccount objectclass that do not have a uidNumber. When such ADD requests are found, the overlay searches the directory for the largest uidNumber, then automatically adds a uidNumber attribute of largest+1 to the entry being added.

This overlay was made possible by copying and pasting lots of code from David Hawes' addpartial.c. This is my first time ever using the openldap API, so any feedback for improvement is greatly appreciated.

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.1
 * Updated: 06.07.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"

static int uidnumber_search_cb( Operation *op, SlapReply *rs);

static slap_overinst uidnumber;
static ObjectClass *oc_posix_account;
static unsigned long max_uid_number;
static char *uid_attr_name = "uidNumber";

/**
 *	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)
{
	Operation nop = *op;
	SlapReply nrs = { REP_RESULT };
	Filter* filter = NULL;
	Entry* to_add = NULL;
	slap_callback cb = { NULL, uidnumber_search_cb, NULL, NULL };
	slap_overinst* on = (slap_overinst *) op->o_bd->bd_info;
	AttributeDescription* ad = NULL;
	Attribute* attr = NULL;
	const char* text;
	char uidstr[64];
	struct berval fstr = BER_BVNULL;
	struct berval rootstr = BER_BVNULL;
	struct berval uidbv = BER_BVNULL;
	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;
			}
		}

	rs->sr_text = NULL;

	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_TRACE, "%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 );

	rc = slap_str2ad( uid_attr_name, &ad, &text );
	if(rc != LDAP_SUCCESS) {
		Debug( LDAP_DEBUG_TRACE, "%s: failed to add uidNumber attribute to entry\n",
					 uidnumber.on_bi.bi_type, 0, 0 );
		return SLAP_CB_CONTINUE;
	}

	max_uid_number++;
	sprintf( uidstr, "%lu", max_uid_number );
	ber_str2bv( uidstr, 0, 0, &uidbv );
	attr_merge_one( to_add, ad, &uidbv, 0 );

	Debug( LDAP_DEBUG_TRACE, "%s: added uidNumber %s to entry\n",
				 uidnumber.on_bi.bi_type, uidstr, 0 );

	return SLAP_CB_CONTINUE;
}

static int uidnumber_search_cb( Operation *op, SlapReply *rs)
{
	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_TRACE, "%s: uidNumber found: %lu\n",
									 uidnumber.on_bi.bi_type, tmp, 0 );
						if( tmp >= max_uid_number ) max_uid_number = tmp;
					}
				}
			}
	}

	return 0;
}

int uidnumber_init() 
{
	uidnumber.on_bi.bi_type = "uidnumber";
	uidnumber.on_bi.bi_op_add = uidnumber_add;

	oc_posix_account = oc_find( "posixAccount" );
	if(oc_posix_account == NULL) {
		Debug( LDAP_DEBUG_TRACE, "%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_SRC=/home/jreed/src/slapd/openldap2.3-2.4.7
CPPFLAGS+=-I${OPENLDAP_SRC}/include -I${OPENLDAP_SRC}/servers/slapd -I${OPENLDAP_SRC}/debian/build/include/
LDFLAGS+=-L/usr/local/openldap-2.4.9
CC=gcc

all: uidnumber.so

uidnumber.so: uidnumber.c
	$(CC) -shared $(CPPFLAGS) $(LDFLAGS) -Wall -o $@ $?

clean:
	rm uidnumber.so


#########################################################
# the rest of this makefile was used for testing purposes
# YMMV

TEST_ARGS=-x -D cn=admin,o=root -y ~/.ds.pwd

install: uidnumber.so
	sudo /etc/init.d/slapd stop
	sudo cp -v $^ /usr/lib/ldap/
	sudo /etc/init.d/slapd start

uninstall:
	rm -fv /usr/lib/ldap/uidnumber.so

test:
	ldapadd $(TEST_ARGS) -f test.ldif

testclean:
	ldapdelete $(TEST_ARGS) "uid=jane2.doe@visn.biz,ou=users,dc=nviznit,dc=com,o=root"
	ldapdelete $(TEST_ARGS) "uid=jane3.doe@visn.biz,ou=users,dc=nviznit,dc=com,o=root"
	ldapdelete $(TEST_ARGS) "uid=jane4.doe@visn.biz,ou=users,dc=nviznit,dc=com,o=root"