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
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"
Joel Reed wrote:
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.
Interesting. Perhaps instead, your overlay should just maintain a fixed entry with a copy of the largest uidNumber in it, instead of searching the entire tree all the time.
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.
On Mon, Jun 09, 2008 at 09:30:24PM -0700, Howard Chu wrote:
Interesting. Perhaps instead, your overlay should just maintain a fixed entry with a copy of the largest uidNumber in it, instead of searching the entire tree all the time.
FWIW, I had the same need, plus allocating gidNumber, sambaSID and whatever. I do with with a dirty hack that filters the output of an accesslog overlay directed to a shell backend.
When I'll have some time, I'd like to write on a slapo-exec, to run external scripts on various conditions. That would be much cleaner.
Emmanuel Dreyfus wrote:
On Mon, Jun 09, 2008 at 09:30:24PM -0700, Howard Chu wrote:
Interesting. Perhaps instead, your overlay should just maintain a fixed entry with a copy of the largest uidNumber in it, instead of searching the entire tree all the time.
FWIW, I had the same need, plus allocating gidNumber, sambaSID and whatever. I do with with a dirty hack that filters the output of an accesslog overlay directed to a shell backend.
When I'll have some time, I'd like to write on a slapo-exec, to run external scripts on various conditions. That would be much cleaner.
fork() is rather hazardous in a threaded program (which is one of the major problems with back-shell). Better to take the approach that back-sock uses, or just wrap some overlay glue around back-sock itself. (Much like slapo-chain is a simple wrapper around back-ldap.)
Am Dienstag, 10. Juni 2008 schrieb Emmanuel Dreyfus:
On Mon, Jun 09, 2008 at 09:30:24PM -0700, Howard Chu wrote:
Interesting. Perhaps instead, your overlay should just maintain a fixed entry with a copy of the largest uidNumber in it, instead of searching the entire tree all the time.
FWIW, I had the same need, plus allocating gidNumber, sambaSID and whatever. I do with with a dirty hack that filters the output of an accesslog overlay directed to a shell backend.
One can extend this to all sorts of attributs (email-Adresses, etc). this leds to the fact, that triggers are missing in OpenLDAP.
We user the same sort of "shell-script-daemon" to implement such "triggers" via inotify ... but thats more than sub-optimal ;-)
When I'll have some time, I'd like to write on a slapo-exec, to run external scripts on various conditions. That would be much cleaner.
I would be very glad to get this sort of overlay, possibly extended to the idea of trigger to any attribute .
Emmanuel Dreyfus wrote:
On Mon, Jun 09, 2008 at 09:30:24PM -0700, Howard Chu wrote:
Interesting. Perhaps instead, your overlay should just maintain a fixed entry with a copy of the largest uidNumber in it, instead of searching the entire tree all the time.
FWIW, I had the same need, plus allocating gidNumber, sambaSID and whatever. I do with with a dirty hack that filters the output of an accesslog overlay directed to a shell backend.
When I'll have some time, I'd like to write on a slapo-exec, to run external scripts on various conditions. That would be much cleaner.
We've also had a similar need. Our solution was to randomly generate the uidNumber and gidNumber, between values of 70000 and 2000000, and then make the attributes unique with the unique overlay. Also, we use the constraint overlay to prevent the value from accidentally getting set to something dangerous (< 100).
Our user base is relatively small, but in the case we randomly generate an existing uid, we just start over.
Our user generation perl script looks something like:
sub new_random_uid { my $range = 1999929999; my $minimum = 70000; return int(rand($range)) + $minimum; }
my $gid_number = new_random_uid(); my $g_samba_number = $gid_number * 2 + 1001; my $uid_number = new_random_uid(); my $u_samba_number = $uid_number * 2 + 1000;
- Dan
Hello,
Dan White wrote:
Emmanuel Dreyfus wrote:
On Mon, Jun 09, 2008 at 09:30:24PM -0700, Howard Chu wrote:
Interesting. Perhaps instead, your overlay should just maintain a fixed entry with a copy of the largest uidNumber in it, instead of searching the entire tree all the time.
FWIW, I had the same need, plus allocating gidNumber, sambaSID and whatever. I do with with a dirty hack that filters the output of an accesslog overlay directed to a shell backend.
When I'll have some time, I'd like to write on a slapo-exec, to run external scripts on various conditions. That would be much cleaner.
Couldn't that either be done via "auditlog" (no shell backend needed, just a fifo) or via "perl backend"? Of course something like "slapo-exec" would be nice, could maybe even be used to synchronize Passwords to Active directory on "change password exop" etc.
bye Christian
On Tuesday 10 June 2008 06:30:24 Howard Chu wrote:
Joel Reed wrote:
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.
Interesting. Perhaps instead, your overlay should just maintain a fixed entry with a copy of the largest uidNumber in it, instead of searching the entire tree all the time.
It may be even nicer if it could be configured to use the sambaUnixIdPool method, which is supported by a number of LDAP frontend tools (such as smbldap-tools). Then the use of both wouldn't result in breakage.
If you don't know how this works, I can provide some details ...
However, this is quite nice ...
Regards, Buchan
Howard Chu wrote:
Joel Reed wrote:
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.
Interesting. Perhaps instead, your overlay should just maintain a fixed entry with a copy of the largest uidNumber in it, instead of searching the entire tree all the time.
I did consider this, but didn't implement it because I was thinking about running in an N-Way Multi-Master configuration. On further reflection, this scheme would probably still not support such a configuration under load.
Obviously, the approach I took doesn't scale well as you point out. I think I will punt on supporting N-Way Multi-Master configs and either use the approach you note above or the sambaUnixIdPool approach noted elsewhere in this thread.
Thanks to everyone who provided feedback. Greatly appreciated.
jr
joel reed wrote:
Howard Chu wrote:
Joel Reed wrote:
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.
Interesting. Perhaps instead, your overlay should just maintain a fixed entry with a copy of the largest uidNumber in it, instead of searching the entire tree all the time.
I did consider this, but didn't implement it because I was thinking about running in an N-Way Multi-Master configuration. On further reflection, this scheme would probably still not support such a configuration under load.
Obviously, the approach I took doesn't scale well as you point out. I think I will punt on supporting N-Way Multi-Master configs and either use the approach you note above or the sambaUnixIdPool approach noted elsewhere in this thread.
It seems the sambaUnixIdPool approach is essentually the same thing, they just have a dedicated entry with uidNumber and gidNumber attributes, recording the next available values.
Thanks to everyone who provided feedback. Greatly appreciated.
In a multimaster scenario the only sane way to handle things is to partition the namespace such that each master is allocating numbers from a totally disjoint range. I would try an approach like this:
Each server allocates uids in blocks, say 1000 at a time. There is an attribute that records the last used (or next available) block. This attribute resides in a dedicated entry that is read and written by all the servers. Each server then records, in a server-specific entry, the last used (or next available) number within that block. You can use the slap_serverID variable to obtain the current server's ID.
so, with 3 masters:
dn: cn=idblock,dc=example,dc=com objectclass: idblock cn: idblock uidNumber: 3000
dn: cn=server1,dc=example,dc=com objectclass: idblock cn: server1 uidNumber: 5
dn: cn=server2,dc=example,dc=com objectclass: idblock cn: server2 uidNumber: 1003
dn: cn=server3,dc=example,dc=com objectclass: idblock cn: server3 uidNumber: 2008
When a particular server allocates all 1000 of the IDs in its current block it will have to go back to the idblock entry and bump that up to the next range. At that point there's the potential for two servers to try to grab the same range, and the resulting conflict would create a big mess.
Another alternative, if you will never change the number of servers involved, is to do away with the central idblock entry and just allocate every-other-Nth ID. E.g., with 3 servers, server1 will allocate 0, 3, 6, 9 ... server2 will allocate 1,4,7,10,... server3 will allocate 2,5,8,11...
That guarantees there will never be conflicts, unless you decide to change the number of masters.
On Tue, Jun 10, 2008 at 12:11:51PM -0700, Howard Chu wrote:
Another alternative, if you will never change the number of servers involved, is to do away with the central idblock entry and just allocate every-other-Nth ID. E.g., with 3 servers, server1 will allocate 0, 3, 6, 9 ... server2 will allocate 1,4,7,10,... server3 will allocate 2,5,8,11...
That guarantees there will never be conflicts, unless you decide to change the number of masters.
As UIDs and GIDs are 32-bit numbers these days they are effectively inexhaustable in most environments. Setting N in your example above to a large number would not be a problem. Thus your 3-server case might choose N=100, giving server1 0,100,200,300,400 and server2 1,101,201,301 etc. The 3-server setup could then safely grow as far as you need.
Doing purely random allocation from a 32-bit number space followed by a sanity check and uniqueness check is likely to be just as safe in practice and has no configuration overhead. Your random numbers must be good though: not crypto-quality, but good enough that the chance of two servers starting at the same number is effectively zero.
(OK, the birthday paradox is not to be trifled with for large N but the randomness only has to be good enough to avoid a clash during the longest feasible replication delay)
Some people have an aesthetic objection to the random allocation system ("Why are the numbers so *big*? We dont need that...") so I still usually use the unique sequential allocation scheme: Perl implementation attached.
Andrew
openldap-software@openldap.org