summaryrefslogtreecommitdiffstats
path: root/libraries/liblutil
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--libraries/liblutil/Makefile.in61
-rw-r--r--libraries/liblutil/avl.c669
-rw-r--r--libraries/liblutil/base64.c308
-rw-r--r--libraries/liblutil/detach.c144
-rw-r--r--libraries/liblutil/entropy.c170
-rw-r--r--libraries/liblutil/getopt.c136
-rw-r--r--libraries/liblutil/getpass.c130
-rw-r--r--libraries/liblutil/getpeereid.c220
-rw-r--r--libraries/liblutil/hash.c77
-rw-r--r--libraries/liblutil/lockf.c118
-rw-r--r--libraries/liblutil/md5.c332
-rw-r--r--libraries/liblutil/memcmp.c33
-rw-r--r--libraries/liblutil/meter.c386
-rw-r--r--libraries/liblutil/ntservice.c509
-rw-r--r--libraries/liblutil/passfile.c110
-rw-r--r--libraries/liblutil/passwd.c1263
-rw-r--r--libraries/liblutil/ptest.c112
-rw-r--r--libraries/liblutil/sasl.c234
-rw-r--r--libraries/liblutil/setproctitle.c78
-rw-r--r--libraries/liblutil/sha1.c288
-rw-r--r--libraries/liblutil/signal.c41
-rw-r--r--libraries/liblutil/slapdmsg.binbin0 -> 116 bytes
-rw-r--r--libraries/liblutil/slapdmsg.h65
-rw-r--r--libraries/liblutil/slapdmsg.mc28
-rw-r--r--libraries/liblutil/slapdmsg.rc2
-rw-r--r--libraries/liblutil/sockpair.c78
-rw-r--r--libraries/liblutil/tavl.c523
-rw-r--r--libraries/liblutil/testavl.c150
-rw-r--r--libraries/liblutil/testtavl.c158
-rw-r--r--libraries/liblutil/utils.c987
-rw-r--r--libraries/liblutil/uuid.c460
31 files changed, 7870 insertions, 0 deletions
diff --git a/libraries/liblutil/Makefile.in b/libraries/liblutil/Makefile.in
new file mode 100644
index 0000000..126352d
--- /dev/null
+++ b/libraries/liblutil/Makefile.in
@@ -0,0 +1,61 @@
+# Makefile for -llutil
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2018 The OpenLDAP Foundation.
+## 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 the file LICENSE in the
+## top-level directory of the distribution or, alternatively, at
+## <http://www.OpenLDAP.org/license.html>.
+
+LIBRARY = liblutil.a
+PROGRAM = testavl
+
+LDAP_INCDIR= ../../include
+LDAP_LIBDIR= ../../libraries
+
+NT_SRCS = ntservice.c
+NT_OBJS = ntservice.o slapdmsg.res
+
+UNIX_SRCS = detach.c
+UNIX_OBJS = detach.o
+
+XLIBS = $(LIBRARY) $(LDAP_LIBLBER_LA)
+
+SRCS = base64.c entropy.c sasl.c signal.c hash.c passfile.c \
+ md5.c passwd.c sha1.c getpass.c lockf.c utils.c uuid.c sockpair.c \
+ avl.c tavl.c \
+ testavl.c \
+ meter.c \
+ @LIBSRCS@ $(@PLAT@_SRCS)
+
+OBJS = base64.o entropy.o sasl.o signal.o hash.o passfile.o \
+ md5.o passwd.o sha1.o getpass.o lockf.o utils.o uuid.o sockpair.o \
+ avl.o tavl.o \
+ meter.o \
+ @LIBOBJS@ $(@PLAT@_OBJS)
+
+testavl: $(XLIBS) testavl.o
+ $(LTLINK) -o $@ testavl.o $(LIBS)
+
+testtavl: $(XLIBS) testtavl.o
+ $(LTLINK) -o $@ testtavl.o $(LIBS)
+
+# These rules are for a Mingw32 build, specifically.
+# It's ok for them to be here because the clean rule is harmless, and
+# slapdmsg.res won't get built unless it's declared in OBJS.
+
+slapdmsg.bin: FORCE
+ @if [ ! -f $@ ]; then cp $(srcdir)/$@ .; fi
+
+slapdmsg.res: slapdmsg.rc slapdmsg.bin
+ windres $< -O coff -o $@
+
+clean-local:
+ $(RM) *.res
+
diff --git a/libraries/liblutil/avl.c b/libraries/liblutil/avl.c
new file mode 100644
index 0000000..8cd88b1
--- /dev/null
+++ b/libraries/liblutil/avl.c
@@ -0,0 +1,669 @@
+/* avl.c - routines to implement an avl tree */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 1998-2018 The OpenLDAP Foundation.
+ * 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 the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* Portions Copyright (c) 1993 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was originally developed by the University of Michigan
+ * (as part of U-MICH LDAP). Additional significant contributors
+ * include:
+ * Howard Y. Chu
+ * Hallvard B. Furuseth
+ * Kurt D. Zeilenga
+ */
+
+#include "portable.h"
+
+#include <limits.h>
+#include <stdio.h>
+#include <ac/stdlib.h>
+
+#ifdef CSRIMALLOC
+#define ber_memalloc malloc
+#define ber_memrealloc realloc
+#define ber_memfree free
+#else
+#include "lber.h"
+#endif
+
+#define AVL_INTERNAL
+#include "avl.h"
+
+/* Maximum tree depth this host's address space could support */
+#define MAX_TREE_DEPTH (sizeof(void *) * CHAR_BIT)
+
+static const int avl_bfs[] = {LH, RH};
+
+/*
+ * avl_insert -- insert a node containing data data into the avl tree
+ * with root root. fcmp is a function to call to compare the data portion
+ * of two nodes. it should take two arguments and return <, >, or == 0,
+ * depending on whether its first argument is <, >, or == its second
+ * argument (like strcmp, e.g.). fdup is a function to call when a duplicate
+ * node is inserted. it should return 0, or -1 and its return value
+ * will be the return value from avl_insert in the case of a duplicate node.
+ * the function will be called with the original node's data as its first
+ * argument and with the incoming duplicate node's data as its second
+ * argument. this could be used, for example, to keep a count with each
+ * node.
+ *
+ * NOTE: this routine may malloc memory
+ */
+int
+avl_insert( Avlnode ** root, void *data, AVL_CMP fcmp, AVL_DUP fdup )
+{
+ Avlnode *t, *p, *s, *q, *r;
+ int a, cmp, ncmp;
+
+ if ( *root == NULL ) {
+ if (( r = (Avlnode *) ber_memalloc( sizeof( Avlnode ))) == NULL ) {
+ return( -1 );
+ }
+ r->avl_link[0] = r->avl_link[1] = NULL;
+ r->avl_data = data;
+ r->avl_bf = EH;
+ *root = r;
+
+ return( 0 );
+ }
+
+ t = NULL;
+ s = p = *root;
+
+ /* find insertion point */
+ while (1) {
+ cmp = fcmp( data, p->avl_data );
+ if ( cmp == 0 )
+ return (*fdup)( p->avl_data, data );
+
+ cmp = (cmp > 0);
+ q = p->avl_link[cmp];
+ if (q == NULL) {
+ /* insert */
+ if (( q = (Avlnode *) ber_memalloc( sizeof( Avlnode ))) == NULL ) {
+ return( -1 );
+ }
+ q->avl_link[0] = q->avl_link[1] = NULL;
+ q->avl_data = data;
+ q->avl_bf = EH;
+
+ p->avl_link[cmp] = q;
+ break;
+ } else if ( q->avl_bf ) {
+ t = p;
+ s = q;
+ }
+ p = q;
+ }
+
+ /* adjust balance factors */
+ cmp = fcmp( data, s->avl_data ) > 0;
+ r = p = s->avl_link[cmp];
+ a = avl_bfs[cmp];
+
+ while ( p != q ) {
+ cmp = fcmp( data, p->avl_data ) > 0;
+ p->avl_bf = avl_bfs[cmp];
+ p = p->avl_link[cmp];
+ }
+
+ /* checks and balances */
+
+ if ( s->avl_bf == EH ) {
+ s->avl_bf = a;
+ return 0;
+ } else if ( s->avl_bf == -a ) {
+ s->avl_bf = EH;
+ return 0;
+ } else if ( s->avl_bf == a ) {
+ cmp = (a > 0);
+ ncmp = !cmp;
+ if ( r->avl_bf == a ) {
+ /* single rotation */
+ p = r;
+ s->avl_link[cmp] = r->avl_link[ncmp];
+ r->avl_link[ncmp] = s;
+ s->avl_bf = 0;
+ r->avl_bf = 0;
+ } else if ( r->avl_bf == -a ) {
+ /* double rotation */
+ p = r->avl_link[ncmp];
+ r->avl_link[ncmp] = p->avl_link[cmp];
+ p->avl_link[cmp] = r;
+ s->avl_link[cmp] = p->avl_link[ncmp];
+ p->avl_link[ncmp] = s;
+
+ if ( p->avl_bf == a ) {
+ s->avl_bf = -a;
+ r->avl_bf = 0;
+ } else if ( p->avl_bf == -a ) {
+ s->avl_bf = 0;
+ r->avl_bf = a;
+ } else {
+ s->avl_bf = 0;
+ r->avl_bf = 0;
+ }
+ p->avl_bf = 0;
+ }
+ /* Update parent */
+ if ( t == NULL )
+ *root = p;
+ else if ( s == t->avl_right )
+ t->avl_right = p;
+ else
+ t->avl_left = p;
+ }
+
+ return 0;
+}
+
+void*
+avl_delete( Avlnode **root, void* data, AVL_CMP fcmp )
+{
+ Avlnode *p, *q, *r, *top;
+ int side, side_bf, shorter, nside;
+
+ /* parent stack */
+ Avlnode *pptr[MAX_TREE_DEPTH];
+ unsigned char pdir[MAX_TREE_DEPTH];
+ int depth = 0;
+
+ if ( *root == NULL )
+ return NULL;
+
+ p = *root;
+
+ while (1) {
+ side = fcmp( data, p->avl_data );
+ if ( !side )
+ break;
+ side = ( side > 0 );
+ pdir[depth] = side;
+ pptr[depth++] = p;
+
+ p = p->avl_link[side];
+ if ( p == NULL )
+ return p;
+ }
+ data = p->avl_data;
+
+ /* If this node has two children, swap so we are deleting a node with
+ * at most one child.
+ */
+ if ( p->avl_link[0] && p->avl_link[1] ) {
+
+ /* find the immediate predecessor <q> */
+ q = p->avl_link[0];
+ side = depth;
+ pdir[depth++] = 0;
+ while (q->avl_link[1]) {
+ pdir[depth] = 1;
+ pptr[depth++] = q;
+ q = q->avl_link[1];
+ }
+ /* swap links */
+ r = p->avl_link[0];
+ p->avl_link[0] = q->avl_link[0];
+ q->avl_link[0] = r;
+
+ q->avl_link[1] = p->avl_link[1];
+ p->avl_link[1] = NULL;
+
+ q->avl_bf = p->avl_bf;
+
+ /* fix stack positions: old parent of p points to q */
+ pptr[side] = q;
+ if ( side ) {
+ r = pptr[side-1];
+ r->avl_link[pdir[side-1]] = q;
+ } else {
+ *root = q;
+ }
+ /* new parent of p points to p */
+ if ( depth-side > 1 ) {
+ r = pptr[depth-1];
+ r->avl_link[1] = p;
+ } else {
+ q->avl_link[0] = p;
+ }
+ }
+
+ /* now <p> has at most one child, get it */
+ q = p->avl_link[0] ? p->avl_link[0] : p->avl_link[1];
+
+ ber_memfree( p );
+
+ if ( !depth ) {
+ *root = q;
+ return data;
+ }
+
+ /* set the child into p's parent */
+ depth--;
+ p = pptr[depth];
+ side = pdir[depth];
+ p->avl_link[side] = q;
+
+ top = NULL;
+ shorter = 1;
+
+ while ( shorter ) {
+ p = pptr[depth];
+ side = pdir[depth];
+ nside = !side;
+ side_bf = avl_bfs[side];
+
+ /* case 1: height unchanged */
+ if ( p->avl_bf == EH ) {
+ /* Tree is now heavier on opposite side */
+ p->avl_bf = avl_bfs[nside];
+ shorter = 0;
+
+ } else if ( p->avl_bf == side_bf ) {
+ /* case 2: taller subtree shortened, height reduced */
+ p->avl_bf = EH;
+ } else {
+ /* case 3: shorter subtree shortened */
+ if ( depth )
+ top = pptr[depth-1]; /* p->parent; */
+ else
+ top = NULL;
+ /* set <q> to the taller of the two subtrees of <p> */
+ q = p->avl_link[nside];
+ if ( q->avl_bf == EH ) {
+ /* case 3a: height unchanged, single rotate */
+ p->avl_link[nside] = q->avl_link[side];
+ q->avl_link[side] = p;
+ shorter = 0;
+ q->avl_bf = side_bf;
+ p->avl_bf = (- side_bf);
+
+ } else if ( q->avl_bf == p->avl_bf ) {
+ /* case 3b: height reduced, single rotate */
+ p->avl_link[nside] = q->avl_link[side];
+ q->avl_link[side] = p;
+ shorter = 1;
+ q->avl_bf = EH;
+ p->avl_bf = EH;
+
+ } else {
+ /* case 3c: height reduced, balance factors opposite */
+ r = q->avl_link[side];
+ q->avl_link[side] = r->avl_link[nside];
+ r->avl_link[nside] = q;
+
+ p->avl_link[nside] = r->avl_link[side];
+ r->avl_link[side] = p;
+
+ if ( r->avl_bf == side_bf ) {
+ q->avl_bf = (- side_bf);
+ p->avl_bf = EH;
+ } else if ( r->avl_bf == (- side_bf)) {
+ q->avl_bf = EH;
+ p->avl_bf = side_bf;
+ } else {
+ q->avl_bf = EH;
+ p->avl_bf = EH;
+ }
+ r->avl_bf = EH;
+ q = r;
+ }
+ /* a rotation has caused <q> (or <r> in case 3c) to become
+ * the root. let <p>'s former parent know this.
+ */
+ if ( top == NULL ) {
+ *root = q;
+ } else if (top->avl_link[0] == p) {
+ top->avl_link[0] = q;
+ } else {
+ top->avl_link[1] = q;
+ }
+ /* end case 3 */
+ p = q;
+ }
+ if ( !depth )
+ break;
+ depth--;
+ } /* end while(shorter) */
+
+ return data;
+}
+
+static int
+avl_inapply( Avlnode *root, AVL_APPLY fn, void* arg, int stopflag )
+{
+ if ( root == 0 )
+ return( AVL_NOMORE );
+
+ if ( root->avl_left != 0 )
+ if ( avl_inapply( root->avl_left, fn, arg, stopflag )
+ == stopflag )
+ return( stopflag );
+
+ if ( (*fn)( root->avl_data, arg ) == stopflag )
+ return( stopflag );
+
+ if ( root->avl_right == 0 )
+ return( AVL_NOMORE );
+ else
+ return( avl_inapply( root->avl_right, fn, arg, stopflag ) );
+}
+
+static int
+avl_postapply( Avlnode *root, AVL_APPLY fn, void* arg, int stopflag )
+{
+ if ( root == 0 )
+ return( AVL_NOMORE );
+
+ if ( root->avl_left != 0 )
+ if ( avl_postapply( root->avl_left, fn, arg, stopflag )
+ == stopflag )
+ return( stopflag );
+
+ if ( root->avl_right != 0 )
+ if ( avl_postapply( root->avl_right, fn, arg, stopflag )
+ == stopflag )
+ return( stopflag );
+
+ return( (*fn)( root->avl_data, arg ) );
+}
+
+static int
+avl_preapply( Avlnode *root, AVL_APPLY fn, void* arg, int stopflag )
+{
+ if ( root == 0 )
+ return( AVL_NOMORE );
+
+ if ( (*fn)( root->avl_data, arg ) == stopflag )
+ return( stopflag );
+
+ if ( root->avl_left != 0 )
+ if ( avl_preapply( root->avl_left, fn, arg, stopflag )
+ == stopflag )
+ return( stopflag );
+
+ if ( root->avl_right == 0 )
+ return( AVL_NOMORE );
+ else
+ return( avl_preapply( root->avl_right, fn, arg, stopflag ) );
+}
+
+/*
+ * avl_apply -- avl tree root is traversed, function fn is called with
+ * arguments arg and the data portion of each node. if fn returns stopflag,
+ * the traversal is cut short, otherwise it continues. Do not use -6 as
+ * a stopflag, as this is what is used to indicate the traversal ran out
+ * of nodes.
+ */
+
+int
+avl_apply( Avlnode *root, AVL_APPLY fn, void* arg, int stopflag, int type )
+{
+ switch ( type ) {
+ case AVL_INORDER:
+ return( avl_inapply( root, fn, arg, stopflag ) );
+ case AVL_PREORDER:
+ return( avl_preapply( root, fn, arg, stopflag ) );
+ case AVL_POSTORDER:
+ return( avl_postapply( root, fn, arg, stopflag ) );
+ default:
+ fprintf( stderr, "Invalid traversal type %d\n", type );
+ return( -1 );
+ }
+
+ /* NOTREACHED */
+}
+
+/*
+ * avl_prefixapply - traverse avl tree root, applying function fprefix
+ * to any nodes that match. fcmp is called with data as its first arg
+ * and the current node's data as its second arg. it should return
+ * 0 if they match, < 0 if data is less, and > 0 if data is greater.
+ * the idea is to efficiently find all nodes that are prefixes of
+ * some key... Like avl_apply, this routine also takes a stopflag
+ * and will return prematurely if fmatch returns this value. Otherwise,
+ * AVL_NOMORE is returned.
+ */
+
+int
+avl_prefixapply(
+ Avlnode *root,
+ void* data,
+ AVL_CMP fmatch,
+ void* marg,
+ AVL_CMP fcmp,
+ void* carg,
+ int stopflag
+)
+{
+ int cmp;
+
+ if ( root == 0 )
+ return( AVL_NOMORE );
+
+ cmp = (*fcmp)( data, root->avl_data /* , carg */);
+ if ( cmp == 0 ) {
+ if ( (*fmatch)( root->avl_data, marg ) == stopflag )
+ return( stopflag );
+
+ if ( root->avl_left != 0 )
+ if ( avl_prefixapply( root->avl_left, data, fmatch,
+ marg, fcmp, carg, stopflag ) == stopflag )
+ return( stopflag );
+
+ if ( root->avl_right != 0 )
+ return( avl_prefixapply( root->avl_right, data, fmatch,
+ marg, fcmp, carg, stopflag ) );
+ else
+ return( AVL_NOMORE );
+
+ } else if ( cmp < 0 ) {
+ if ( root->avl_left != 0 )
+ return( avl_prefixapply( root->avl_left, data, fmatch,
+ marg, fcmp, carg, stopflag ) );
+ } else {
+ if ( root->avl_right != 0 )
+ return( avl_prefixapply( root->avl_right, data, fmatch,
+ marg, fcmp, carg, stopflag ) );
+ }
+
+ return( AVL_NOMORE );
+}
+
+/*
+ * avl_free -- traverse avltree root, freeing the memory it is using.
+ * the dfree() is called to free the data portion of each node. The
+ * number of items actually freed is returned.
+ */
+
+int
+avl_free( Avlnode *root, AVL_FREE dfree )
+{
+ int nleft, nright;
+
+ if ( root == 0 )
+ return( 0 );
+
+ nleft = nright = 0;
+ if ( root->avl_left != 0 )
+ nleft = avl_free( root->avl_left, dfree );
+
+ if ( root->avl_right != 0 )
+ nright = avl_free( root->avl_right, dfree );
+
+ if ( dfree )
+ (*dfree)( root->avl_data );
+ ber_memfree( root );
+
+ return( nleft + nright + 1 );
+}
+
+/*
+ * avl_find -- search avltree root for a node with data data. the function
+ * cmp is used to compare things. it is called with data as its first arg
+ * and the current node data as its second. it should return 0 if they match,
+ * < 0 if arg1 is less than arg2 and > 0 if arg1 is greater than arg2.
+ */
+
+Avlnode *
+avl_find2( Avlnode *root, const void *data, AVL_CMP fcmp )
+{
+ int cmp;
+
+ while ( root != 0 && (cmp = (*fcmp)( data, root->avl_data )) != 0 ) {
+ cmp = cmp > 0;
+ root = root->avl_link[cmp];
+ }
+ return root;
+}
+
+void*
+avl_find( Avlnode *root, const void* data, AVL_CMP fcmp )
+{
+ int cmp;
+
+ while ( root != 0 && (cmp = (*fcmp)( data, root->avl_data )) != 0 ) {
+ cmp = cmp > 0;
+ root = root->avl_link[cmp];
+ }
+
+ return( root ? root->avl_data : 0 );
+}
+
+/*
+ * avl_find_lin -- search avltree root linearly for a node with data data.
+ * the function cmp is used to compare things. it is called with data as its
+ * first arg and the current node data as its second. it should return 0 if
+ * they match, non-zero otherwise.
+ */
+
+void*
+avl_find_lin( Avlnode *root, const void* data, AVL_CMP fcmp )
+{
+ void* res;
+
+ if ( root == 0 )
+ return( NULL );
+
+ if ( (*fcmp)( data, root->avl_data ) == 0 )
+ return( root->avl_data );
+
+ if ( root->avl_left != 0 )
+ if ( (res = avl_find_lin( root->avl_left, data, fcmp ))
+ != NULL )
+ return( res );
+
+ if ( root->avl_right == 0 )
+ return( NULL );
+ else
+ return( avl_find_lin( root->avl_right, data, fcmp ) );
+}
+
+/* NON-REENTRANT INTERFACE */
+
+static void* *avl_list;
+static int avl_maxlist;
+static int avl_nextlist;
+
+#define AVL_GRABSIZE 100
+
+/* ARGSUSED */
+static int
+avl_buildlist( void* data, void* arg )
+{
+ static int slots;
+
+ if ( avl_list == (void* *) 0 ) {
+ avl_list = (void* *) ber_memalloc(AVL_GRABSIZE * sizeof(void*));
+ slots = AVL_GRABSIZE;
+ avl_maxlist = 0;
+ } else if ( avl_maxlist == slots ) {
+ slots += AVL_GRABSIZE;
+ avl_list = (void* *) ber_memrealloc( (char *) avl_list,
+ (unsigned) slots * sizeof(void*));
+ }
+
+ avl_list[ avl_maxlist++ ] = data;
+
+ return( 0 );
+}
+
+/*
+ * avl_getfirst() and avl_getnext() are provided as alternate tree
+ * traversal methods, to be used when a single function cannot be
+ * provided to be called with every node in the tree. avl_getfirst()
+ * traverses the tree and builds a linear list of all the nodes,
+ * returning the first node. avl_getnext() returns the next thing
+ * on the list built by avl_getfirst(). This means that avl_getfirst()
+ * can take a while, and that the tree should not be messed with while
+ * being traversed in this way, and that multiple traversals (even of
+ * different trees) cannot be active at once.
+ */
+
+void*
+avl_getfirst( Avlnode *root )
+{
+ if ( avl_list ) {
+ ber_memfree( (char *) avl_list);
+ avl_list = (void* *) 0;
+ }
+ avl_maxlist = 0;
+ avl_nextlist = 0;
+
+ if ( root == 0 )
+ return( 0 );
+
+ (void) avl_apply( root, avl_buildlist, (void*) 0, -1, AVL_INORDER );
+
+ return( avl_list[ avl_nextlist++ ] );
+}
+
+void*
+avl_getnext( void )
+{
+ if ( avl_list == 0 )
+ return( 0 );
+
+ if ( avl_nextlist == avl_maxlist ) {
+ ber_memfree( (void*) avl_list);
+ avl_list = (void* *) 0;
+ return( 0 );
+ }
+
+ return( avl_list[ avl_nextlist++ ] );
+}
+
+/* end non-reentrant code */
+
+
+int
+avl_dup_error( void* left, void* right )
+{
+ return( -1 );
+}
+
+int
+avl_dup_ok( void* left, void* right )
+{
+ return( 0 );
+}
diff --git a/libraries/liblutil/base64.c b/libraries/liblutil/base64.c
new file mode 100644
index 0000000..1862643
--- /dev/null
+++ b/libraries/liblutil/base64.c
@@ -0,0 +1,308 @@
+/* base64.c -- routines to encode/decode base64 data */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 1998-2018 The OpenLDAP Foundation.
+ * Portions Copyright 1998-2003 Kurt D. Zeilenga.
+ * Portions Copyright 1995 IBM Corporation.
+ * 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 the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* Portions Copyright (c) 1996, 1998 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+/* This work is based upon Base64 routines (developed by IBM) found
+ * Berkeley Internet Name Daemon (BIND) as distributed by ISC. They
+ * were adapted for inclusion in OpenLDAP Software by Kurt D. Zeilenga.
+ */
+
+#include "portable.h"
+
+#include <ac/assert.h>
+#include <ac/stdlib.h>
+#include <ac/ctype.h>
+#include <ac/string.h>
+
+/* include socket.h to get sys/types.h and/or winsock2.h */
+#include <ac/socket.h>
+
+#include "lutil.h"
+
+static const char Base64[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+static const char Pad64 = '=';
+
+/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt)
+ The following encoding technique is taken from RFC 1521 by Borenstein
+ and Freed. It is reproduced here in a slightly edited form for
+ convenience.
+
+ A 65-character subset of US-ASCII is used, enabling 6 bits to be
+ represented per printable character. (The extra 65th character, "=",
+ is used to signify a special processing function.)
+
+ The encoding process represents 24-bit groups of input bits as output
+ strings of 4 encoded characters. Proceeding from left to right, a
+ 24-bit input group is formed by concatenating 3 8-bit input groups.
+ These 24 bits are then treated as 4 concatenated 6-bit groups, each
+ of which is translated into a single digit in the base64 alphabet.
+
+ Each 6-bit group is used as an index into an array of 64 printable
+ characters. The character referenced by the index is placed in the
+ output string.
+
+ Table 1: The Base64 Alphabet
+
+ Value Encoding Value Encoding Value Encoding Value Encoding
+ 0 A 17 R 34 i 51 z
+ 1 B 18 S 35 j 52 0
+ 2 C 19 T 36 k 53 1
+ 3 D 20 U 37 l 54 2
+ 4 E 21 V 38 m 55 3
+ 5 F 22 W 39 n 56 4
+ 6 G 23 X 40 o 57 5
+ 7 H 24 Y 41 p 58 6
+ 8 I 25 Z 42 q 59 7
+ 9 J 26 a 43 r 60 8
+ 10 K 27 b 44 s 61 9
+ 11 L 28 c 45 t 62 +
+ 12 M 29 d 46 u 63 /
+ 13 N 30 e 47 v
+ 14 O 31 f 48 w (pad) =
+ 15 P 32 g 49 x
+ 16 Q 33 h 50 y
+
+ Special processing is performed if fewer than 24 bits are available
+ at the end of the data being encoded. A full encoding quantum is
+ always completed at the end of a quantity. When fewer than 24 input
+ bits are available in an input group, zero bits are added (on the
+ right) to form an integral number of 6-bit groups. Padding at the
+ end of the data is performed using the '=' character.
+
+ Since all base64 input is an integral number of octets, only the
+ -------------------------------------------------
+ following cases can arise:
+
+ (1) the final quantum of encoding input is an integral
+ multiple of 24 bits; here, the final unit of encoded
+ output will be an integral multiple of 4 characters
+ with no "=" padding,
+ (2) the final quantum of encoding input is exactly 8 bits;
+ here, the final unit of encoded output will be two
+ characters followed by two "=" padding characters, or
+ (3) the final quantum of encoding input is exactly 16 bits;
+ here, the final unit of encoded output will be three
+ characters followed by one "=" padding character.
+ */
+
+int
+lutil_b64_ntop(
+ u_char const *src,
+ size_t srclength,
+ char *target,
+ size_t targsize)
+{
+ size_t datalength = 0;
+ u_char input[3];
+ u_char output[4];
+ size_t i;
+
+ while (2 < srclength) {
+ input[0] = *src++;
+ input[1] = *src++;
+ input[2] = *src++;
+ srclength -= 3;
+
+ output[0] = input[0] >> 2;
+ output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
+ output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
+ output[3] = input[2] & 0x3f;
+ assert(output[0] < 64);
+ assert(output[1] < 64);
+ assert(output[2] < 64);
+ assert(output[3] < 64);
+
+ if (datalength + 4 > targsize)
+ return (-1);
+ target[datalength++] = Base64[output[0]];
+ target[datalength++] = Base64[output[1]];
+ target[datalength++] = Base64[output[2]];
+ target[datalength++] = Base64[output[3]];
+ }
+
+ /* Now we worry about padding. */
+ if (0 != srclength) {
+ /* Get what's left. */
+ input[0] = input[1] = input[2] = '\0';
+ for (i = 0; i < srclength; i++)
+ input[i] = *src++;
+
+ output[0] = input[0] >> 2;
+ output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
+ output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
+ assert(output[0] < 64);
+ assert(output[1] < 64);
+ assert(output[2] < 64);
+
+ if (datalength + 4 > targsize)
+ return (-1);
+ target[datalength++] = Base64[output[0]];
+ target[datalength++] = Base64[output[1]];
+ if (srclength == 1)
+ target[datalength++] = Pad64;
+ else
+ target[datalength++] = Base64[output[2]];
+ target[datalength++] = Pad64;
+ }
+ if (datalength >= targsize)
+ return (-1);
+ target[datalength] = '\0'; /* Returned value doesn't count \0. */
+ return (datalength);
+}
+
+/* skips all whitespace anywhere.
+ converts characters, four at a time, starting at (or after)
+ src from base - 64 numbers into three 8 bit bytes in the target area.
+ it returns the number of data bytes stored at the target, or -1 on error.
+ */
+
+int
+lutil_b64_pton(
+ char const *src,
+ u_char *target,
+ size_t targsize)
+{
+ int tarindex, state, ch;
+ char *pos;
+
+ state = 0;
+ tarindex = 0;
+
+ while ((ch = *src++) != '\0') {
+ if (isascii(ch) && isspace(ch)) /* Skip whitespace anywhere. */
+ continue;
+
+ if (ch == Pad64)
+ break;
+
+ pos = strchr(Base64, ch);
+ if (pos == 0) /* A non-base64 character. */
+ return (-1);
+
+ switch (state) {
+ case 0:
+ if (target) {
+ if ((size_t)tarindex >= targsize)
+ return (-1);
+ target[tarindex] = (pos - Base64) << 2;
+ }
+ state = 1;
+ break;
+ case 1:
+ if (target) {
+ if ((size_t)tarindex + 1 >= targsize)
+ return (-1);
+ target[tarindex] |= (pos - Base64) >> 4;
+ target[tarindex+1] = ((pos - Base64) & 0x0f)
+ << 4 ;
+ }
+ tarindex++;
+ state = 2;
+ break;
+ case 2:
+ if (target) {
+ if ((size_t)tarindex + 1 >= targsize)
+ return (-1);
+ target[tarindex] |= (pos - Base64) >> 2;
+ target[tarindex+1] = ((pos - Base64) & 0x03)
+ << 6;
+ }
+ tarindex++;
+ state = 3;
+ break;
+ case 3:
+ if (target) {
+ if ((size_t)tarindex >= targsize)
+ return (-1);
+ target[tarindex] |= (pos - Base64);
+ }
+ tarindex++;
+ state = 0;
+ break;
+ default:
+ abort();
+ }
+ }
+
+ /*
+ * We are done decoding Base-64 chars. Let's see if we ended
+ * on a byte boundary, and/or with erroneous trailing characters.
+ */
+
+ if (ch == Pad64) { /* We got a pad char. */
+ ch = *src++; /* Skip it, get next. */
+ switch (state) {
+ case 0: /* Invalid = in first position */
+ case 1: /* Invalid = in second position */
+ return (-1);
+
+ case 2: /* Valid, means one byte of info */
+ /* Skip any number of spaces. */
+ for ((void)NULL; ch != '\0'; ch = *src++)
+ if (! (isascii(ch) && isspace(ch)))
+ break;
+ /* Make sure there is another trailing = sign. */
+ if (ch != Pad64)
+ return (-1);
+ ch = *src++; /* Skip the = */
+ /* Fall through to "single trailing =" case. */
+ /* FALLTHROUGH */
+
+ case 3: /* Valid, means two bytes of info */
+ /*
+ * We know this char is an =. Is there anything but
+ * whitespace after it?
+ */
+ for ((void)NULL; ch != '\0'; ch = *src++)
+ if (! (isascii(ch) && isspace(ch)))
+ return (-1);
+
+ /*
+ * Now make sure for cases 2 and 3 that the "extra"
+ * bits that slopped past the last full byte were
+ * zeros. If we don't check them, they become a
+ * subliminal channel.
+ */
+ if (target && target[tarindex] != 0)
+ return (-1);
+ }
+ } else {
+ /*
+ * We ended by seeing the end of the string. Make sure we
+ * have no partial bytes lying around.
+ */
+ if (state != 0)
+ return (-1);
+ }
+
+ return (tarindex);
+}
diff --git a/libraries/liblutil/detach.c b/libraries/liblutil/detach.c
new file mode 100644
index 0000000..da9dcca
--- /dev/null
+++ b/libraries/liblutil/detach.c
@@ -0,0 +1,144 @@
+/* detach.c -- routines to daemonize a process */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 1998-2018 The OpenLDAP Foundation.
+ * 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 the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/*
+ * Copyright (c) 1990, 1994 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+/* This work was originally developed by the University of Michigan
+ * and distributed as part of U-MICH LDAP.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/stdlib.h>
+#include <ac/signal.h>
+#include <ac/socket.h>
+#include <ac/unistd.h>
+
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#ifdef HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#include "lutil.h"
+
+int
+lutil_detach( int debug, int do_close )
+{
+ int i, sd, nbits, pid;
+
+#ifdef HAVE_SYSCONF
+ nbits = sysconf( _SC_OPEN_MAX );
+#elif defined(HAVE_GETDTABLESIZE)
+ nbits = getdtablesize();
+#else
+ nbits = FD_SETSIZE;
+#endif
+
+#ifdef FD_SETSIZE
+ if ( nbits > FD_SETSIZE ) {
+ nbits = FD_SETSIZE;
+ }
+#endif /* FD_SETSIZE */
+
+ if ( debug == 0 ) {
+ for ( i = 0; i < 5; i++ ) {
+#ifdef HAVE_THR
+ pid = fork1();
+#else
+ pid = fork();
+#endif
+ switch ( pid )
+ {
+ case -1:
+ sleep( 5 );
+ continue;
+
+ case 0:
+ break;
+
+ default:
+ return pid;
+ }
+ break;
+ }
+
+ if ( (sd = open( "/dev/null", O_RDWR )) == -1 &&
+ (sd = open( "/dev/null", O_RDONLY )) == -1 &&
+ /* Panic -- open *something* */
+ (sd = open( "/", O_RDONLY )) == -1 ) {
+ perror("/dev/null");
+ } else {
+ /* redirect stdin, stdout, stderr to /dev/null */
+ dup2( sd, STDIN_FILENO );
+ dup2( sd, STDOUT_FILENO );
+ dup2( sd, STDERR_FILENO );
+
+ switch( sd ) {
+ default:
+ close( sd );
+ case STDIN_FILENO:
+ case STDOUT_FILENO:
+ case STDERR_FILENO:
+ break;
+ }
+ }
+
+ if ( do_close ) {
+ /* close everything else */
+ for ( i = 0; i < nbits; i++ ) {
+ if( i != STDIN_FILENO &&
+ i != STDOUT_FILENO &&
+ i != STDERR_FILENO )
+ {
+ close( i );
+ }
+ }
+ }
+
+#ifdef CHDIR_TO_ROOT
+ (void) chdir( "/" );
+#endif
+
+#ifdef HAVE_SETSID
+ (void) setsid();
+#elif defined(TIOCNOTTY)
+ if ( (sd = open( "/dev/tty", O_RDWR )) != -1 ) {
+ (void) ioctl( sd, TIOCNOTTY, NULL );
+ (void) close( sd );
+ }
+#endif
+ }
+
+#ifdef SIGPIPE
+ (void) SIGNAL( SIGPIPE, SIG_IGN );
+#endif
+ return 0;
+}
diff --git a/libraries/liblutil/entropy.c b/libraries/liblutil/entropy.c
new file mode 100644
index 0000000..4017363
--- /dev/null
+++ b/libraries/liblutil/entropy.c
@@ -0,0 +1,170 @@
+/* entropy.c -- routines for providing pseudo-random data */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 1999-2018 The OpenLDAP Foundation.
+ * Portions Copyright 1999-2003 Kurt D. Zeilenga.
+ * 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 the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* This work was initially developed by Kurt D. Zeilenga for
+ * inclusion in OpenLDAP Software based, in part, on publically
+ * available works (as noted below).
+ */
+
+#include "portable.h"
+
+#include <ac/string.h>
+#include <ac/time.h>
+#include <ac/unistd.h>
+
+#ifdef HAVE_PROCESS_H
+#include <process.h>
+#endif
+
+#include <fcntl.h>
+
+#include <lutil.h>
+#include <lutil_md5.h>
+
+/*
+ * lutil_entropy() provides nbytes of entropy in buf.
+ * Quality offerred is suitable for one-time uses, such as "once" keys.
+ * Values may not be suitable for multi-time uses.
+ *
+ * Note: Callers are encouraged to provide additional bytes of
+ * of entropy in the buf argument. This information is used in
+ * fallback mode to improve the quality of bytes returned.
+ *
+ * This routinue should be extended to support additional sources
+ * of entropy.
+ */
+int lutil_entropy( unsigned char *buf, ber_len_t nbytes )
+{
+ if( nbytes == 0 ) return 0;
+
+#ifdef URANDOM_DEVICE
+#define URANDOM_NREADS 4
+ /* Linux and *BSD offer a urandom device */
+ {
+ int rc, fd, n=0;
+
+ fd = open( URANDOM_DEVICE, O_RDONLY );
+
+ if( fd < 0 ) return -1;
+
+ do {
+ rc = read( fd, buf, nbytes );
+ if( rc <= 0 ) break;
+
+ buf+=rc;
+ nbytes-=rc;
+
+ if( ++n >= URANDOM_NREADS ) break;
+ } while( nbytes > 0 );
+
+ close(fd);
+ return nbytes > 0 ? -1 : 0;
+ }
+#elif defined(PROV_RSA_FULL)
+ {
+ /* Not used since _WIN32_WINNT not set... */
+ HCRYPTPROV hProv = 0;
+
+ /* Get handle to user default provider */
+ if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0)) {
+ return -1;
+ }
+
+ /* Generate random initialization vector */
+ if(!CryptGenRandom(hProv, (DWORD) nbytes, (BYTE *) buf)) {
+ return -1;
+ }
+
+ /* Release provider handle */
+ if(hProv != 0) CryptReleaseContext(hProv, 0);
+
+ return 0;
+ }
+#else
+ {
+ /* based upon Phil Karn's "practical randomness" idea
+ * but implementation 100% OpenLDAP. So don't blame Phil.
+ *
+ * Worse case is that this is a MD5 hash of a counter, if
+ * MD5 is a strong cryptographic hash, this should be fairly
+ * resistant to attack
+ */
+
+ /*
+ * the caller may need to provide external synchronization OR
+ * provide entropy (in buf) to ensure quality results as
+ * access to this counter may not be atomic.
+ */
+ static int counter = 0;
+ ber_len_t n;
+
+ struct rdata_s {
+ int counter;
+
+ unsigned char *buf;
+ struct rdata_s *stack;
+
+ pid_t pid;
+
+#ifdef HAVE_GETTIMEOFDAY
+ struct timeval tv;
+#else
+ time_t time;
+#endif
+
+ unsigned long junk; /* purposely not initialized */
+ } rdata;
+
+ /* make sure rdata differs for each process */
+ rdata.pid = getpid();
+
+ /* make sure rdata differs for each program */
+ rdata.buf = buf;
+ rdata.stack = &rdata;
+
+ for( n = 0; n < nbytes; n += 16 ) {
+ struct lutil_MD5Context ctx;
+ unsigned char digest[16];
+
+ /* poor resolution */
+#ifdef HAVE_GETTIMEOFDAY
+ (void) gettimeofday( &rdata.tv, NULL );
+#else
+ (void) time( &rdata.time );
+#endif
+
+ /* make sure rdata differs */
+ rdata.counter = ++counter;
+ rdata.pid++;
+ rdata.junk++;
+
+ lutil_MD5Init( &ctx );
+ lutil_MD5Update( &ctx, (unsigned char *) &rdata, sizeof( rdata ) );
+
+ /* allow caller to provided additional entropy */
+ lutil_MD5Update( &ctx, buf, nbytes );
+
+ lutil_MD5Final( digest, &ctx );
+
+ AC_MEMCPY( &buf[n], digest,
+ nbytes - n >= 16 ? 16 : nbytes - n );
+ }
+
+ return 0;
+ }
+#endif
+ return -1;
+}
diff --git a/libraries/liblutil/getopt.c b/libraries/liblutil/getopt.c
new file mode 100644
index 0000000..40fe1e4
--- /dev/null
+++ b/libraries/liblutil/getopt.c
@@ -0,0 +1,136 @@
+/* getopt.c -- replacement getopt(3) routines */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 1998-2018 The OpenLDAP Foundation.
+ * Portions Copyright 1998-2003 Kurt D. Zeilenga.
+ * 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 the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* This work is based upon the public-domain getopt(3) routines
+ * developed by AT&T. Modified by Kurt D. Zeilenga for inclusion
+ * into OpenLDAP Software. Significant contributors include:
+ * Howard Chu
+ */
+
+#include "portable.h"
+
+#ifndef HAVE_GETOPT
+
+#include <stdio.h>
+
+#include <ac/string.h>
+#include <ac/unistd.h>
+
+#ifdef HAVE_IO_H
+#include <io.h>
+#endif
+
+#include "lutil.h"
+
+#ifndef STDERR_FILENO
+#define STDERR_FILENO 2
+#endif
+
+int opterr = 1;
+int optind = 1;
+int optopt;
+char * optarg;
+
+#ifdef HAVE_EBCDIC
+extern int _trans_argv;
+#endif
+
+static void ERR (char * const argv[], const char * s, char c)
+{
+#ifdef DF_TRACE_DEBUG
+printf("DF_TRACE_DEBUG: static void ERR () in getopt.c\n");
+#endif
+ if (opterr)
+ {
+ char *ptr, outbuf[4096];
+
+ ptr = lutil_strncopy(outbuf, argv[0], sizeof(outbuf) - 2);
+ ptr = lutil_strncopy(ptr, s, sizeof(outbuf)-2 -(ptr-outbuf));
+ *ptr++ = c;
+ *ptr++ = '\n';
+#ifdef HAVE_EBCDIC
+ __atoe_l(outbuf, ptr - outbuf);
+#endif
+ (void) write(STDERR_FILENO,outbuf,ptr - outbuf);
+ }
+}
+
+int getopt (int argc, char * const argv [], const char * opts)
+{
+ static int sp = 1, error = (int) '?';
+ static char sw = '-', eos = '\0', arg = ':';
+ register char c, * cp;
+
+#ifdef DF_TRACE_DEBUG
+printf("DF_TRACE_DEBUG: int getopt () in getopt.c\n");
+#endif
+
+#ifdef HAVE_EBCDIC
+ if (_trans_argv) {
+ int i;
+ for (i=0; i<argc; i++) __etoa(argv[i]);
+ _trans_argv = 0;
+ }
+#endif
+ if (sp == 1)
+ {
+ if (optind >= argc || argv[optind][0] != sw
+ || argv[optind][1] == eos)
+ return EOF;
+ else if (strcmp(argv[optind],"--") == 0)
+ {
+ optind++;
+ return EOF;
+ }
+ }
+ c = argv[optind][sp];
+ optopt = (int) c;
+ if (c == arg || (cp = strchr(opts,c)) == NULL)
+ {
+ ERR(argv,_(": illegal option--"),c);
+ if (argv[optind][++sp] == eos)
+ {
+ optind++;
+ sp = 1;
+ }
+ return error;
+ }
+ else if (*++cp == arg)
+ {
+ if (argv[optind][sp + 1] != eos)
+ optarg = &argv[optind++][sp + 1];
+ else if (++optind >= argc)
+ {
+ ERR(argv,_(": option requires an argument--"),c);
+ sp = 1;
+ return error;
+ }
+ else
+ optarg = argv[optind++];
+ sp = 1;
+ }
+ else
+ {
+ if (argv[optind][++sp] == eos)
+ {
+ sp = 1;
+ optind++;
+ }
+ optarg = NULL;
+ }
+ return (int) c;
+}
+#endif /* HAVE_GETOPT */
diff --git a/libraries/liblutil/getpass.c b/libraries/liblutil/getpass.c
new file mode 100644
index 0000000..bfa844f
--- /dev/null
+++ b/libraries/liblutil/getpass.c
@@ -0,0 +1,130 @@
+/* getpass.c -- get password from user */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 1998-2018 The OpenLDAP Foundation.
+ * Portions Copyright 1998-2003 Kurt D. Zeilenga.
+ * Portions Copyright 2009 Howard Chu.
+ * 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 the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* Portions Copyright (c) 1992, 1993 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+/* This work was originally developed by the University of Michigan
+ * and distributed as part of U-MICH LDAP. It was adapted for use in
+ * -llutil by Kurt D. Zeilenga and subsequently rewritten by Howard Chu.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/stdlib.h>
+
+#include <ac/ctype.h>
+#include <ac/signal.h>
+#include <ac/string.h>
+#include <ac/termios.h>
+#include <ac/time.h>
+#include <ac/unistd.h>
+
+#ifndef HAVE_GETPASSPHRASE
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#ifdef HAVE_CONIO_H
+#include <conio.h>
+#endif
+
+#include <lber.h>
+#include <ldap.h>
+
+#include "ldap_defaults.h"
+
+#define PBUF 512
+
+#ifdef HAVE_WINSOCK
+#define TTY "con:"
+#else
+#define TTY "/dev/tty"
+#endif
+
+char *
+lutil_getpass( const char *prompt )
+{
+ static char pbuf[PBUF];
+ FILE *fi;
+ int c;
+ unsigned i;
+#if defined(HAVE_TERMIOS_H) || defined(HAVE_SGTTY_H)
+ TERMIO_TYPE ttyb;
+ TERMFLAG_TYPE flags;
+ RETSIGTYPE (*sig)( int sig );
+#endif
+
+ if( prompt == NULL ) prompt = _("Password: ");
+
+#ifdef DEBUG
+ if (debug & D_TRACE)
+ printf("->getpass(%s)\n", prompt);
+#endif
+
+#if defined(HAVE_TERMIOS_H) || defined(HAVE_SGTTY_H)
+ if ((fi = fopen(TTY, "r")) == NULL)
+ fi = stdin;
+ else
+ setbuf(fi, (char *)NULL);
+ if (fi != stdin) {
+ if (GETATTR(fileno(fi), &ttyb) < 0)
+ perror("GETATTR");
+ sig = SIGNAL (SIGINT, SIG_IGN);
+ flags = GETFLAGS( ttyb );
+ SETFLAGS( ttyb, flags & ~ECHO );
+ if (SETATTR(fileno(fi), &ttyb) < 0)
+ perror("SETATTR");
+ }
+#else
+ fi = stdin;
+#endif
+ fprintf(stderr, "%s", prompt);
+ fflush(stderr);
+ i = 0;
+ while ( (c = getc(fi)) != EOF && c != '\n' && c != '\r' )
+ if ( i < (sizeof(pbuf)-1) )
+ pbuf[i++] = c;
+#if defined(HAVE_TERMIOS_H) || defined(HAVE_SGTTY_H)
+ /* tidy up */
+ if (fi != stdin) {
+ fprintf(stderr, "\n");
+ fflush(stderr);
+ SETFLAGS( ttyb, flags );
+ if (SETATTR(fileno(fi), &ttyb) < 0)
+ perror("SETATTR");
+ (void) SIGNAL (SIGINT, sig);
+ (void) fclose(fi);
+ }
+#endif
+ if ( c == EOF )
+ return( NULL );
+ pbuf[i] = '\0';
+ return (pbuf);
+}
+
+#endif /* !NEED_GETPASSPHRASE */
diff --git a/libraries/liblutil/getpeereid.c b/libraries/liblutil/getpeereid.c
new file mode 100644
index 0000000..056caef
--- /dev/null
+++ b/libraries/liblutil/getpeereid.c
@@ -0,0 +1,220 @@
+/* getpeereid.c */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2000-2018 The OpenLDAP Foundation.
+ * 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 the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1 /* Needed for glibc struct ucred */
+#endif
+
+#include "portable.h"
+
+#ifndef HAVE_GETPEEREID
+
+#include <sys/types.h>
+#include <ac/unistd.h>
+
+#include <ac/socket.h>
+#include <ac/errno.h>
+
+#ifdef HAVE_GETPEERUCRED
+#include <ucred.h>
+#endif
+
+#ifdef LDAP_PF_LOCAL_SENDMSG
+#include <lber.h>
+#ifdef HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
+#include <sys/stat.h>
+#endif
+
+#ifdef HAVE_SYS_UCRED_H
+#ifdef HAVE_GRP_H
+#include <grp.h> /* for NGROUPS on Tru64 5.1 */
+#endif
+#include <sys/ucred.h>
+#endif
+
+#include <stdlib.h>
+
+int lutil_getpeereid( int s, uid_t *euid, gid_t *egid
+#ifdef LDAP_PF_LOCAL_SENDMSG
+ , struct berval *peerbv
+#endif
+ )
+{
+#ifdef LDAP_PF_LOCAL
+#if defined( HAVE_GETPEERUCRED )
+ ucred_t *uc = NULL;
+ if( getpeerucred( s, &uc ) == 0 ) {
+ *euid = ucred_geteuid( uc );
+ *egid = ucred_getegid( uc );
+ ucred_free( uc );
+ return 0;
+ }
+
+#elif defined( SO_PEERCRED )
+ struct ucred peercred;
+ ber_socklen_t peercredlen = sizeof peercred;
+
+ if(( getsockopt( s, SOL_SOCKET, SO_PEERCRED,
+ (void *)&peercred, &peercredlen ) == 0 )
+ && ( peercredlen == sizeof peercred ))
+ {
+ *euid = peercred.uid;
+ *egid = peercred.gid;
+ return 0;
+ }
+
+#elif defined( LOCAL_PEERCRED )
+ struct xucred peercred;
+ ber_socklen_t peercredlen = sizeof peercred;
+
+ if(( getsockopt( s, LOCAL_PEERCRED, 1,
+ (void *)&peercred, &peercredlen ) == 0 )
+ && ( peercred.cr_version == XUCRED_VERSION ))
+ {
+ *euid = peercred.cr_uid;
+ *egid = peercred.cr_gid;
+ return 0;
+ }
+#elif defined( LDAP_PF_LOCAL_SENDMSG ) && defined( MSG_WAITALL )
+ int err, fd;
+ struct iovec iov;
+ struct msghdr msg = {0};
+# ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
+# ifndef CMSG_SPACE
+# define CMSG_SPACE(len) (_CMSG_ALIGN(sizeof(struct cmsghdr)) + _CMSG_ALIGN(len))
+# endif
+# ifndef CMSG_LEN
+# define CMSG_LEN(len) (_CMSG_ALIGN(sizeof(struct cmsghdr)) + (len))
+# endif
+ struct {
+ struct cmsghdr cm;
+ int fd;
+ } control_st;
+ struct cmsghdr *cmsg;
+# endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL */
+ struct stat st;
+ struct sockaddr_un lname, rname;
+ ber_socklen_t llen, rlen;
+
+ rlen = sizeof(rname);
+ llen = sizeof(lname);
+ memset( &lname, 0, sizeof( lname ));
+ getsockname(s, (struct sockaddr *)&lname, &llen);
+
+ iov.iov_base = peerbv->bv_val;
+ iov.iov_len = peerbv->bv_len;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ peerbv->bv_len = 0;
+
+# ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
+ msg.msg_control = &control_st;
+ msg.msg_controllen = sizeof( struct cmsghdr ) + sizeof( int ); /* no padding! */
+
+ cmsg = CMSG_FIRSTHDR( &msg );
+# else
+ msg.msg_accrights = (char *)&fd;
+ msg.msg_accrightslen = sizeof(fd);
+# endif
+
+ /*
+ * AIX returns a bogus file descriptor if recvmsg() is
+ * called with MSG_PEEK (is this a bug?). Hence we need
+ * to receive the Abandon PDU.
+ */
+ err = recvmsg( s, &msg, MSG_WAITALL );
+ if( err >= 0 &&
+# ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
+ cmsg->cmsg_len == CMSG_LEN( sizeof(int) ) &&
+ cmsg->cmsg_level == SOL_SOCKET &&
+ cmsg->cmsg_type == SCM_RIGHTS
+# else
+ msg.msg_accrightslen == sizeof(int)
+# endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL*/
+ ) {
+ int mode = S_IFIFO|S_ISUID|S_IRWXU;
+
+ /* We must receive a valid descriptor, it must be a pipe,
+ * it must only be accessible by its owner, and it must
+ * have the name of our socket written on it.
+ */
+ peerbv->bv_len = err;
+# ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
+ fd = (*(int *)CMSG_DATA( cmsg ));
+# endif
+ err = fstat( fd, &st );
+ if ( err == 0 )
+ rlen = read(fd, &rname, rlen);
+ close(fd);
+ if( err == 0 && st.st_mode == mode &&
+ llen == rlen && !memcmp(&lname, &rname, llen))
+ {
+ *euid = st.st_uid;
+ *egid = st.st_gid;
+ return 0;
+ }
+ }
+#elif defined(SOCKCREDSIZE)
+ struct msghdr msg;
+ ber_socklen_t crmsgsize;
+ void *crmsg;
+ struct cmsghdr *cmp;
+ struct sockcred *sc;
+
+ memset(&msg, 0, sizeof msg);
+ crmsgsize = CMSG_SPACE(SOCKCREDSIZE(NGROUPS));
+ if (crmsgsize == 0) goto sc_err;
+ crmsg = malloc(crmsgsize);
+ if (crmsg == NULL) goto sc_err;
+ memset(crmsg, 0, crmsgsize);
+
+ msg.msg_control = crmsg;
+ msg.msg_controllen = crmsgsize;
+
+ if (recvmsg(s, &msg, 0) < 0) {
+ free(crmsg);
+ goto sc_err;
+ }
+
+ if (msg.msg_controllen == 0 || (msg.msg_flags & MSG_CTRUNC) != 0) {
+ free(crmsg);
+ goto sc_err;
+ }
+
+ cmp = CMSG_FIRSTHDR(&msg);
+ if (cmp->cmsg_level != SOL_SOCKET || cmp->cmsg_type != SCM_CREDS) {
+ printf("nocreds\n");
+ goto sc_err;
+ }
+
+ sc = (struct sockcred *)(void *)CMSG_DATA(cmp);
+
+ *euid = sc->sc_euid;
+ *egid = sc->sc_egid;
+
+ free(crmsg);
+ return 0;
+
+sc_err:
+#endif
+#endif /* LDAP_PF_LOCAL */
+
+ return -1;
+}
+
+#endif /* HAVE_GETPEEREID */
diff --git a/libraries/liblutil/hash.c b/libraries/liblutil/hash.c
new file mode 100644
index 0000000..2f20385
--- /dev/null
+++ b/libraries/liblutil/hash.c
@@ -0,0 +1,77 @@
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2000-2018 The OpenLDAP Foundation.
+ * Portions Copyright 2000-2003 Kurt D. Zeilenga.
+ * 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 the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+
+/* This implements the Fowler / Noll / Vo (FNV-1) hash algorithm.
+ * A summary of the algorithm can be found at:
+ * http://www.isthe.com/chongo/tech/comp/fnv/index.html
+ */
+
+#include "portable.h"
+
+#include <lutil_hash.h>
+
+/* offset and prime for 32-bit FNV-1 */
+#define HASH_OFFSET 0x811c9dc5U
+#define HASH_PRIME 16777619
+
+
+/*
+ * Initialize context
+ */
+void
+lutil_HASHInit( struct lutil_HASHContext *ctx )
+{
+ ctx->hash = HASH_OFFSET;
+}
+
+/*
+ * Update hash
+ */
+void
+lutil_HASHUpdate(
+ struct lutil_HASHContext *ctx,
+ const unsigned char *buf,
+ ber_len_t len )
+{
+ const unsigned char *p, *e;
+ ber_uint_t h;
+
+ p = buf;
+ e = &buf[len];
+
+ h = ctx->hash;
+
+ while( p < e ) {
+ h *= HASH_PRIME;
+ h ^= *p++;
+ }
+
+ ctx->hash = h;
+}
+
+/*
+ * Save hash
+ */
+void
+lutil_HASHFinal( unsigned char *digest, struct lutil_HASHContext *ctx )
+{
+ ber_uint_t h = ctx->hash;
+
+ digest[0] = h & 0xffU;
+ digest[1] = (h>>8) & 0xffU;
+ digest[2] = (h>>16) & 0xffU;
+ digest[3] = (h>>24) & 0xffU;
+}
diff --git a/libraries/liblutil/lockf.c b/libraries/liblutil/lockf.c
new file mode 100644
index 0000000..32a8f0e
--- /dev/null
+++ b/libraries/liblutil/lockf.c
@@ -0,0 +1,118 @@
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 1998-2018 The OpenLDAP Foundation.
+ * 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 the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+
+/*
+ * File Locking Routines
+ *
+ * Implementations (in order of preference)
+ * - lockf
+ * - fcntl
+ * - flock
+ *
+ * Other implementations will be added as needed.
+ *
+ * NOTE: lutil_lockf() MUST block until an exclusive lock is acquired.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+#include <ac/unistd.h>
+
+#undef LOCK_API
+
+#if defined(HAVE_LOCKF) && defined(F_LOCK)
+# define USE_LOCKF 1
+# define LOCK_API "lockf"
+#endif
+
+#if !defined(LOCK_API) && defined(HAVE_FCNTL)
+# ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+# endif
+# ifdef F_WRLCK
+# define USE_FCNTL 1
+# define LOCK_API "fcntl"
+# endif
+#endif
+
+#if !defined(LOCK_API) && defined(HAVE_FLOCK)
+# ifdef HAVE_SYS_FILE_H
+# include <sys/file.h>
+# endif
+# define USE_FLOCK 1
+# define LOCK_API "flock"
+#endif
+
+#if !defined(USE_LOCKF) && !defined(USE_FCNTL) && !defined(USE_FLOCK)
+int lutil_lockf ( int fd ) {
+ fd = fd;
+ return 0;
+}
+
+int lutil_unlockf ( int fd ) {
+ fd = fd;
+ return 0;
+}
+#endif
+
+#ifdef USE_LOCKF
+int lutil_lockf ( int fd ) {
+ /* use F_LOCK instead of F_TLOCK, ie: block */
+ return lockf( fd, F_LOCK, 0 );
+}
+
+int lutil_unlockf ( int fd ) {
+ return lockf( fd, F_ULOCK, 0 );
+}
+#endif
+
+#ifdef USE_FCNTL
+int lutil_lockf ( int fd ) {
+ struct flock file_lock;
+
+ memset( &file_lock, '\0', sizeof( file_lock ) );
+ file_lock.l_type = F_WRLCK;
+ file_lock.l_whence = SEEK_SET;
+ file_lock.l_start = 0;
+ file_lock.l_len = 0;
+
+ /* use F_SETLKW instead of F_SETLK, ie: block */
+ return( fcntl( fd, F_SETLKW, &file_lock ) );
+}
+
+int lutil_unlockf ( int fd ) {
+ struct flock file_lock;
+
+ memset( &file_lock, '\0', sizeof( file_lock ) );
+ file_lock.l_type = F_UNLCK;
+ file_lock.l_whence = SEEK_SET;
+ file_lock.l_start = 0;
+ file_lock.l_len = 0;
+
+ return( fcntl ( fd, F_SETLKW, &file_lock ) );
+}
+#endif
+
+#ifdef USE_FLOCK
+int lutil_lockf ( int fd ) {
+ /* use LOCK_EX instead of LOCK_EX|LOCK_NB, ie: block */
+ return flock( fd, LOCK_EX );
+}
+
+int lutil_unlockf ( int fd ) {
+ return flock( fd, LOCK_UN );
+}
+#endif
diff --git a/libraries/liblutil/md5.c b/libraries/liblutil/md5.c
new file mode 100644
index 0000000..207ada7
--- /dev/null
+++ b/libraries/liblutil/md5.c
@@ -0,0 +1,332 @@
+/* md5.c -- MD5 message-digest algorithm */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 1998-2018 The OpenLDAP Foundation.
+ * 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 the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* This work was adapted for inclusion in OpenLDAP Software by
+ * Kurt D. Zeilenga based upon code developed by Colin Plumb
+ * and subsequently modified by Jim Kingdon.
+ */
+
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+/* This code was modified in 1997 by Jim Kingdon of Cyclic Software to
+ not require an integer type which is exactly 32 bits. This work
+ draws on the changes for the same purpose by Tatu Ylonen
+ <ylo@cs.hut.fi> as part of SSH, but since I didn't actually use
+ that code, there is no copyright issue. I hereby disclaim
+ copyright in any changes I have made; this code remains in the
+ public domain. */
+
+#include "portable.h"
+
+#include <ac/string.h>
+
+/* include socket.h to get sys/types.h and/or winsock2.h */
+#include <ac/socket.h>
+
+#include <lutil_md5.h>
+
+/* Little-endian byte-swapping routines. Note that these do not
+ depend on the size of datatypes such as ber_uint_t, nor do they require
+ us to detect the endianness of the machine we are running on. It
+ is possible they should be macros for speed, but I would be
+ surprised if they were a performance bottleneck for MD5. */
+
+static ber_uint_t
+getu32( const unsigned char *addr )
+{
+ return (((((unsigned long)addr[3] << 8) | addr[2]) << 8)
+ | addr[1]) << 8 | addr[0];
+}
+
+static void
+putu32( ber_uint_t data, unsigned char *addr )
+{
+ addr[0] = (unsigned char)data;
+ addr[1] = (unsigned char)(data >> 8);
+ addr[2] = (unsigned char)(data >> 16);
+ addr[3] = (unsigned char)(data >> 24);
+}
+
+/*
+ * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void
+lutil_MD5Init( struct lutil_MD5Context *ctx )
+{
+ ctx->buf[0] = 0x67452301;
+ ctx->buf[1] = 0xefcdab89;
+ ctx->buf[2] = 0x98badcfe;
+ ctx->buf[3] = 0x10325476;
+
+ ctx->bits[0] = 0;
+ ctx->bits[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void
+lutil_MD5Update(
+ struct lutil_MD5Context *ctx,
+ const unsigned char *buf,
+ ber_len_t len
+)
+{
+ ber_uint_t t;
+
+ /* Update bitcount */
+
+ t = ctx->bits[0];
+ if ((ctx->bits[0] = (t + ((ber_uint_t)len << 3)) & 0xffffffff) < t)
+ ctx->bits[1]++; /* Carry from low to high */
+ ctx->bits[1] += len >> 29;
+
+ t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
+
+ /* Handle any leading odd-sized chunks */
+
+ if ( t ) {
+ unsigned char *p = ctx->in + t;
+
+ t = 64-t;
+ if (len < t) {
+ AC_MEMCPY(p, buf, len);
+ return;
+ }
+ AC_MEMCPY(p, buf, t);
+ lutil_MD5Transform(ctx->buf, ctx->in);
+ buf += t;
+ len -= t;
+ }
+
+ /* Process data in 64-byte chunks */
+
+ while (len >= 64) {
+ AC_MEMCPY(ctx->in, buf, 64);
+ lutil_MD5Transform(ctx->buf, ctx->in);
+ buf += 64;
+ len -= 64;
+ }
+
+ /* Handle any remaining bytes of data. */
+
+ AC_MEMCPY(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void
+lutil_MD5Final( unsigned char *digest, struct lutil_MD5Context *ctx )
+{
+ unsigned count;
+ unsigned char *p;
+
+ /* Compute number of bytes mod 64 */
+ count = (ctx->bits[0] >> 3) & 0x3F;
+
+ /* Set the first char of padding to 0x80. This is safe since there is
+ always at least one byte free */
+ p = ctx->in + count;
+ *p++ = 0x80;
+
+ /* Bytes of padding needed to make 64 bytes */
+ count = 64 - 1 - count;
+
+ /* Pad out to 56 mod 64 */
+ if (count < 8) {
+ /* Two lots of padding: Pad the first block to 64 bytes */
+ memset(p, '\0', count);
+ lutil_MD5Transform(ctx->buf, ctx->in);
+
+ /* Now fill the next block with 56 bytes */
+ memset(ctx->in, '\0', 56);
+ } else {
+ /* Pad block to 56 bytes */
+ memset(p, '\0', count-8);
+ }
+
+ /* Append length in bits and transform */
+ putu32(ctx->bits[0], ctx->in + 56);
+ putu32(ctx->bits[1], ctx->in + 60);
+
+ lutil_MD5Transform(ctx->buf, ctx->in);
+ putu32(ctx->buf[0], digest);
+ putu32(ctx->buf[1], digest + 4);
+ putu32(ctx->buf[2], digest + 8);
+ putu32(ctx->buf[3], digest + 12);
+ memset(ctx, '\0', sizeof(*ctx)); /* In case it's sensitive */
+}
+
+#ifndef ASM_MD5
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+ ( w += f(x, y, z) + data, w &= 0xffffffff, w = w<<s | w>>(32-s), w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data. MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+void
+lutil_MD5Transform( ber_uint_t *buf, const unsigned char *inraw )
+{
+ register ber_uint_t a, b, c, d;
+ ber_uint_t in[16];
+ int i;
+
+ for (i = 0; i < 16; ++i)
+ in[i] = getu32 (inraw + 4 * i);
+
+ a = buf[0];
+ b = buf[1];
+ c = buf[2];
+ d = buf[3];
+
+ MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478, 7);
+ MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12);
+ MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17);
+ MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22);
+ MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf, 7);
+ MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12);
+ MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17);
+ MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22);
+ MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8, 7);
+ MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12);
+ MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17);
+ MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22);
+ MD5STEP(F1, a, b, c, d, in[12]+0x6b901122, 7);
+ MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12);
+ MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17);
+ MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22);
+
+ MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562, 5);
+ MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340, 9);
+ MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14);
+ MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20);
+ MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d, 5);
+ MD5STEP(F2, d, a, b, c, in[10]+0x02441453, 9);
+ MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14);
+ MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20);
+ MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6, 5);
+ MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6, 9);
+ MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14);
+ MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20);
+ MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905, 5);
+ MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8, 9);
+ MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14);
+ MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20);
+
+ MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942, 4);
+ MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11);
+ MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16);
+ MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23);
+ MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44, 4);
+ MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11);
+ MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16);
+ MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23);
+ MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6, 4);
+ MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11);
+ MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16);
+ MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23);
+ MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039, 4);
+ MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11);
+ MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16);
+ MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23);
+
+ MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244, 6);
+ MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10);
+ MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15);
+ MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21);
+ MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3, 6);
+ MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10);
+ MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15);
+ MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21);
+ MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f, 6);
+ MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10);
+ MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15);
+ MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21);
+ MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82, 6);
+ MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10);
+ MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15);
+ MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21);
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
+#endif
+
+#ifdef TEST
+/* Simple test program. Can use it to manually run the tests from
+ RFC1321 for example. */
+#include <stdio.h>
+
+int
+main (int argc, char **argv )
+{
+ struct lutil_MD5Context context;
+ unsigned char checksum[LUTIL_MD5_BYTES];
+ int i;
+ int j;
+
+ if (argc < 2)
+ {
+ fprintf (stderr, "usage: %s string-to-hash\n", argv[0]);
+ return EXIT_FAILURE;
+ }
+ for (j = 1; j < argc; ++j)
+ {
+ printf ("MD5 (\"%s\") = ", argv[j]);
+ lutil_MD5Init (&context);
+ lutil_MD5Update (&context, argv[j], strlen (argv[j]));
+ lutil_MD5Final (checksum, &context);
+ for (i = 0; i < LUTIL_MD5_BYTES; i++)
+ {
+ printf ("%02x", (unsigned int) checksum[i]);
+ }
+ printf ("\n");
+ }
+ return EXIT_SUCCESS;
+}
+#endif /* TEST */
diff --git a/libraries/liblutil/memcmp.c b/libraries/liblutil/memcmp.c
new file mode 100644
index 0000000..d4a6ae0
--- /dev/null
+++ b/libraries/liblutil/memcmp.c
@@ -0,0 +1,33 @@
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 1998-2018 The OpenLDAP Foundation.
+ * 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 the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+
+#include "portable.h"
+
+#include <ac/string.h>
+
+/*
+ * Memory Compare
+ */
+int
+(lutil_memcmp)(const void *v1, const void *v2, size_t n)
+{
+ if (n != 0) {
+ const unsigned char *s1=v1, *s2=v2;
+ do {
+ if (*s1++ != *s2++) return *--s1 - *--s2;
+ } while (--n != 0);
+ }
+ return 0;
+}
diff --git a/libraries/liblutil/meter.c b/libraries/liblutil/meter.c
new file mode 100644
index 0000000..7b5543c
--- /dev/null
+++ b/libraries/liblutil/meter.c
@@ -0,0 +1,386 @@
+/* meter.c - lutil_meter meters */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright (c) 2009 by Emily Backes, Symas Corp.
+ * 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 the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was initially developed by Emily Backes for inclusion
+ * in OpenLDAP software.
+ */
+
+#include "portable.h"
+#include "lutil_meter.h"
+
+#include <ac/assert.h>
+#include <ac/string.h>
+
+int
+lutil_time_string (
+ char *dest,
+ int duration,
+ int max_terms)
+{
+ static const int time_div[] = {31556952,
+ 604800,
+ 86400,
+ 3600,
+ 60,
+ 1,
+ 0};
+ const int * time_divp = time_div;
+ static const char * time_name_ch = "ywdhms";
+ const char * time_name_chp = time_name_ch;
+ int term_count = 0;
+ char *buf = dest;
+ int time_quot;
+
+ assert ( max_terms >= 2 ); /* room for "none" message */
+
+ if ( duration < 0 ) {
+ *dest = '\0';
+ return 1;
+ }
+ if ( duration == 0 ) {
+ strcpy( dest, "none" );
+ return 0;
+ }
+ while ( term_count < max_terms && duration > 0 ) {
+ if (duration > *time_divp) {
+ time_quot = duration / *time_divp;
+ duration %= *time_divp;
+ if (time_quot > 99) {
+ return 1;
+ } else {
+ *(buf++) = time_quot / 10 + '0';
+ *(buf++) = time_quot % 10 + '0';
+ *(buf++) = *time_name_chp;
+ ++term_count;
+ }
+ }
+ if ( *(++time_divp) == 0) duration = 0;
+ ++time_name_chp;
+ }
+ *buf = '\0';
+ return 0;
+}
+
+int
+lutil_get_now (double *now)
+{
+#ifdef HAVE_GETTIMEOFDAY
+ struct timeval tv;
+
+ assert( now );
+ gettimeofday( &tv, NULL );
+ *now = ((double) tv.tv_sec) + (((double) tv.tv_usec) / 1000000.0);
+ return 0;
+#else
+ time_t tm;
+
+ assert( now );
+ time( &tm );
+ *now = (double) tm;
+ return 0;
+#endif
+}
+
+int
+lutil_meter_open (
+ lutil_meter_t *meter,
+ const lutil_meter_display_t *display,
+ const lutil_meter_estimator_t *estimator,
+ size_t goal_value)
+{
+ int rc;
+
+ assert( meter != NULL );
+ assert( display != NULL );
+ assert( estimator != NULL );
+
+ if (goal_value < 1) return -1;
+
+ memset( (void*) meter, 0, sizeof( lutil_meter_t ));
+ meter->display = display;
+ meter->estimator = estimator;
+ lutil_get_now( &meter->start_time );
+ meter->last_update = meter->start_time;
+ meter->goal_value = goal_value;
+ meter->last_position = 0;
+
+ rc = meter->display->display_open( &meter->display_data );
+ if( rc != 0 ) return rc;
+
+ rc = meter->estimator->estimator_open( &meter->estimator_data );
+ if( rc != 0 ) {
+ meter->display->display_close( &meter->display_data );
+ return rc;
+ }
+
+ return 0;
+}
+
+int
+lutil_meter_update (
+ lutil_meter_t *meter,
+ size_t position,
+ int force)
+{
+ static const double display_rate = 0.5;
+ double frac, cycle_length, speed, now;
+ time_t remaining_time, elapsed;
+ int rc;
+
+ assert( meter != NULL );
+
+ lutil_get_now( &now );
+
+ if ( !force && now - meter->last_update < display_rate ) return 0;
+
+ frac = ((double)position) / ((double) meter->goal_value);
+ elapsed = now - meter->start_time;
+ if (frac <= 0.0) return 0;
+ if (frac >= 1.0) {
+ rc = meter->display->display_update(
+ &meter->display_data,
+ 1.0,
+ 0,
+ (time_t) elapsed,
+ ((double)position) / elapsed);
+ } else {
+ rc = meter->estimator->estimator_update(
+ &meter->estimator_data,
+ meter->start_time,
+ frac,
+ &remaining_time );
+ if ( rc == 0 ) {
+ cycle_length = now - meter->last_update;
+ speed = cycle_length > 0.0 ?
+ ((double)(position - meter->last_position))
+ / cycle_length :
+ 0.0;
+ rc = meter->display->display_update(
+ &meter->display_data,
+ frac,
+ remaining_time,
+ (time_t) elapsed,
+ speed);
+ if ( rc == 0 ) {
+ meter->last_update = now;
+ meter->last_position = position;
+ }
+ }
+ }
+
+ return rc;
+}
+
+int
+lutil_meter_close (lutil_meter_t *meter)
+{
+ meter->estimator->estimator_close( &meter->estimator_data );
+ meter->display->display_close( &meter->display_data );
+
+ return 0;
+}
+
+/* Default display and estimator */
+typedef struct {
+ int buffer_length;
+ char * buffer;
+ int need_eol;
+ int phase;
+ FILE *output;
+} text_display_state_t;
+
+static int
+text_open (void ** display_datap)
+{
+ static const int default_buffer_length = 81;
+ text_display_state_t *data;
+
+ assert( display_datap != NULL );
+ data = calloc( 1, sizeof( text_display_state_t ));
+ assert( data != NULL );
+ data->buffer_length = default_buffer_length;
+ data->buffer = calloc( 1, default_buffer_length );
+ assert( data->buffer != NULL );
+ data->output = stderr;
+ *display_datap = data;
+ return 0;
+}
+
+static int
+text_update (
+ void **display_datap,
+ double frac,
+ time_t remaining_time,
+ time_t elapsed,
+ double byte_rate)
+{
+ text_display_state_t *data;
+ char *buf, *buf_end;
+
+ assert( display_datap != NULL );
+ assert( *display_datap != NULL );
+ data = (text_display_state_t*) *display_datap;
+
+ if ( data->output == NULL ) return 1;
+
+ buf = data->buffer;
+ buf_end = buf + data->buffer_length - 1;
+
+/* |#################### 100.00% eta 1d19h elapsed 23w 7d23h15m12s spd nnnn.n M/s */
+
+ {
+ /* spinner */
+ static const int phase_mod = 8;
+ static const char phase_char[] = "_.-*\"*-.";
+ *buf++ = phase_char[data->phase % phase_mod];
+ data->phase++;
+ }
+
+ {
+ /* bar */
+ static const int bar_length = 20;
+ static const double bar_lengthd = 20.0;
+ static const char fill_char = '#';
+ static const char blank_char = ' ';
+ char *bar_end = buf + bar_length;
+ char *bar_pos = frac < 0.0 ?
+ buf :
+ frac < 1.0 ?
+ buf + (int) (bar_lengthd * frac) :
+ bar_end;
+
+ assert( (buf_end - buf) > bar_length );
+ while ( buf < bar_end ) {
+ *buf = buf < bar_pos ?
+ fill_char : blank_char;
+ ++buf;
+ }
+ }
+
+ {
+ /* percent */
+ (void) snprintf( buf, buf_end-buf, "%7.2f%%", 100.0*frac );
+ buf += 8;
+ }
+
+ {
+ /* eta and elapsed */
+ char time_buffer[19];
+ int rc;
+ rc = lutil_time_string( time_buffer, remaining_time, 2);
+ if (rc == 0)
+ snprintf( buf, buf_end-buf, " eta %6s", time_buffer );
+ buf += 5+6;
+ rc = lutil_time_string( time_buffer, elapsed, 5);
+ if (rc == 0)
+ snprintf( buf, buf_end-buf, " elapsed %15s",
+ time_buffer );
+ buf += 9+15;
+ }
+
+ {
+ /* speed */
+ static const char prefixes[] = " kMGTPEZY";
+ const char *prefix_chp = prefixes;
+
+ while (*prefix_chp && byte_rate >= 1024.0) {
+ byte_rate /= 1024.0;
+ ++prefix_chp;
+ }
+ if ( byte_rate >= 1024.0 ) {
+ snprintf( buf, buf_end-buf, " fast!" );
+ buf += 6;
+ } else {
+ snprintf( buf, buf_end-buf, " spd %5.1f %c/s",
+ byte_rate,
+ *prefix_chp);
+ buf += 5+6+4;
+ }
+ }
+
+ (void) fprintf( data->output,
+ "\r%-79s",
+ data->buffer );
+ data->need_eol = 1;
+ return 0;
+}
+
+static int
+text_close (void ** display_datap)
+{
+ text_display_state_t *data;
+
+ if (display_datap) {
+ if (*display_datap) {
+ data = (text_display_state_t*) *display_datap;
+ if (data->output && data->need_eol)
+ fputs ("\n", data->output);
+ if (data->buffer)
+ free( data->buffer );
+ free( data );
+ }
+ *display_datap = NULL;
+ }
+ return 0;
+}
+
+static int
+null_open_close (void **datap)
+{
+ assert( datap );
+ *datap = NULL;
+ return 0;
+}
+
+static int
+linear_update (
+ void **estimator_datap,
+ double start,
+ double frac,
+ time_t *remaining)
+{
+ double now;
+ double elapsed;
+
+ assert( estimator_datap != NULL );
+ assert( *estimator_datap == NULL );
+ assert( start > 0.0 );
+ assert( frac >= 0.0 );
+ assert( frac <= 1.0 );
+ assert( remaining != NULL );
+ lutil_get_now( &now );
+
+ elapsed = now-start;
+ assert( elapsed >= 0.0 );
+
+ if ( frac == 0.0 ) {
+ return 1;
+ } else if ( frac >= 1.0 ) {
+ *remaining = 0;
+ return 0;
+ } else {
+ *remaining = (time_t) (elapsed/frac-elapsed+0.5);
+ return 0;
+ }
+}
+
+const lutil_meter_display_t lutil_meter_text_display = {
+ text_open, text_update, text_close
+};
+
+const lutil_meter_estimator_t lutil_meter_linear_estimator = {
+ null_open_close, linear_update, null_open_close
+};
diff --git a/libraries/liblutil/ntservice.c b/libraries/liblutil/ntservice.c
new file mode 100644
index 0000000..a42b484
--- /dev/null
+++ b/libraries/liblutil/ntservice.c
@@ -0,0 +1,509 @@
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 1998-2018 The OpenLDAP Foundation.
+ * 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 the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+
+/*
+ * NT Service manager utilities for OpenLDAP services
+ */
+
+#include "portable.h"
+
+#ifdef HAVE_NT_SERVICE_MANAGER
+
+#include <ac/stdlib.h>
+#include <ac/string.h>
+
+#include <stdio.h>
+
+#include <windows.h>
+#include <winsvc.h>
+
+#include <ldap.h>
+
+#include "ldap_pvt_thread.h"
+
+#include "ldap_defaults.h"
+
+#include "slapdmsg.h"
+
+#define SCM_NOTIFICATION_INTERVAL 5000
+#define THIRTY_SECONDS (30 * 1000)
+
+int is_NT_Service; /* is this is an NT service? */
+
+SERVICE_STATUS lutil_ServiceStatus;
+SERVICE_STATUS_HANDLE hlutil_ServiceStatus;
+
+ldap_pvt_thread_cond_t started_event, stopped_event;
+ldap_pvt_thread_t start_status_tid, stop_status_tid;
+
+void (*stopfunc)(int);
+
+static char *GetLastErrorString( void );
+
+int lutil_srv_install(LPCTSTR lpszServiceName, LPCTSTR lpszDisplayName,
+ LPCTSTR lpszBinaryPathName, int auto_start)
+{
+ HKEY hKey;
+ DWORD dwValue, dwDisposition;
+ SC_HANDLE schSCManager, schService;
+ char *sp = strrchr( lpszBinaryPathName, '\\');
+
+ if ( sp ) sp = strchr(sp, ' ');
+ if ( sp ) *sp = '\0';
+ fprintf( stderr, "The install path is %s.\n", lpszBinaryPathName );
+ if ( sp ) *sp = ' ';
+ if ((schSCManager = OpenSCManager( NULL, NULL, SC_MANAGER_CONNECT|SC_MANAGER_CREATE_SERVICE ) ) != NULL )
+ {
+ if ((schService = CreateService(
+ schSCManager,
+ lpszServiceName,
+ lpszDisplayName,
+ SERVICE_ALL_ACCESS,
+ SERVICE_WIN32_OWN_PROCESS,
+ auto_start ? SERVICE_AUTO_START : SERVICE_DEMAND_START,
+ SERVICE_ERROR_NORMAL,
+ lpszBinaryPathName,
+ NULL, NULL, NULL, NULL, NULL)) != NULL)
+ {
+ char regpath[132];
+ CloseServiceHandle(schService);
+ CloseServiceHandle(schSCManager);
+
+ snprintf( regpath, sizeof regpath,
+ "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\%s",
+ lpszServiceName );
+ /* Create the registry key for event logging to the Windows NT event log. */
+ if ( RegCreateKeyEx(HKEY_LOCAL_MACHINE,
+ regpath, 0,
+ "REG_SZ", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey,
+ &dwDisposition) != ERROR_SUCCESS)
+ {
+ fprintf( stderr, "RegCreateKeyEx() failed. GetLastError=%lu (%s)\n", GetLastError(), GetLastErrorString() );
+ RegCloseKey(hKey);
+ return(0);
+ }
+ if ( sp ) *sp = '\0';
+ if ( RegSetValueEx(hKey, "EventMessageFile", 0, REG_EXPAND_SZ, lpszBinaryPathName, strlen(lpszBinaryPathName) + 1) != ERROR_SUCCESS)
+ {
+ fprintf( stderr, "RegSetValueEx(EventMessageFile) failed. GetLastError=%lu (%s)\n", GetLastError(), GetLastErrorString() );
+ RegCloseKey(hKey);
+ return(0);
+ }
+
+ dwValue = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE;
+ if ( RegSetValueEx(hKey, "TypesSupported", 0, REG_DWORD, (LPBYTE) &dwValue, sizeof(DWORD)) != ERROR_SUCCESS)
+ {
+ fprintf( stderr, "RegCreateKeyEx(TypesSupported) failed. GetLastError=%lu (%s)\n", GetLastError(), GetLastErrorString() );
+ RegCloseKey(hKey);
+ return(0);
+ }
+ RegCloseKey(hKey);
+ return(1);
+ }
+ else
+ {
+ fprintf( stderr, "CreateService() failed. GetLastError=%lu (%s)\n", GetLastError(), GetLastErrorString() );
+ CloseServiceHandle(schSCManager);
+ return(0);
+ }
+ }
+ else
+ fprintf( stderr, "OpenSCManager() failed. GetLastError=%lu (%s)\n", GetLastError(), GetLastErrorString() );
+ return(0);
+}
+
+
+int lutil_srv_remove(LPCTSTR lpszServiceName, LPCTSTR lpszBinaryPathName)
+{
+ SC_HANDLE schSCManager, schService;
+
+ fprintf( stderr, "The installed path is %s.\n", lpszBinaryPathName );
+ if ((schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT|SC_MANAGER_CREATE_SERVICE)) != NULL )
+ {
+ if ((schService = OpenService(schSCManager, lpszServiceName, DELETE)) != NULL)
+ {
+ if ( DeleteService(schService) == TRUE)
+ {
+ CloseServiceHandle(schService);
+ CloseServiceHandle(schSCManager);
+ return(1);
+ } else {
+ fprintf( stderr, "DeleteService() failed. GetLastError=%lu (%s)\n", GetLastError(), GetLastErrorString() );
+ fprintf( stderr, "The %s service has not been removed.\n", lpszBinaryPathName);
+ CloseServiceHandle(schService);
+ CloseServiceHandle(schSCManager);
+ return(0);
+ }
+ } else {
+ fprintf( stderr, "OpenService() failed. GetLastError=%lu (%s)\n", GetLastError(), GetLastErrorString() );
+ CloseServiceHandle(schSCManager);
+ return(0);
+ }
+ }
+ else
+ fprintf( stderr, "OpenSCManager() failed. GetLastError=%lu (%s)\n", GetLastError(), GetLastErrorString() );
+ return(0);
+}
+
+
+#if 0 /* unused */
+DWORD
+svc_installed (LPTSTR lpszServiceName, LPTSTR lpszBinaryPathName)
+{
+ char buf[256];
+ HKEY key;
+ DWORD rc;
+ DWORD type;
+ long len;
+
+ strcpy(buf, TEXT("SYSTEM\\CurrentControlSet\\Services\\"));
+ strcat(buf, lpszServiceName);
+ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, buf, 0, KEY_QUERY_VALUE, &key) != ERROR_SUCCESS)
+ return(-1);
+
+ rc = 0;
+ if (lpszBinaryPathName) {
+ len = sizeof(buf);
+ if (RegQueryValueEx(key, "ImagePath", NULL, &type, buf, &len) == ERROR_SUCCESS) {
+ if (strcmp(lpszBinaryPathName, buf))
+ rc = -1;
+ }
+ }
+ RegCloseKey(key);
+ return(rc);
+}
+
+
+DWORD
+svc_running (LPTSTR lpszServiceName)
+{
+ SC_HANDLE service;
+ SC_HANDLE scm;
+ DWORD rc;
+ SERVICE_STATUS ss;
+
+ if (!(scm = OpenSCManager(NULL, NULL, GENERIC_READ)))
+ return(GetLastError());
+
+ rc = 1;
+ service = OpenService(scm, lpszServiceName, SERVICE_QUERY_STATUS);
+ if (service) {
+ if (!QueryServiceStatus(service, &ss))
+ rc = GetLastError();
+ else if (ss.dwCurrentState != SERVICE_STOPPED)
+ rc = 0;
+ CloseServiceHandle(service);
+ }
+ CloseServiceHandle(scm);
+ return(rc);
+}
+#endif
+
+static void *start_status_routine( void *ptr )
+{
+ DWORD wait_result;
+ int done = 0;
+
+ while ( !done )
+ {
+ wait_result = WaitForSingleObject( started_event, SCM_NOTIFICATION_INTERVAL );
+ switch ( wait_result )
+ {
+ case WAIT_ABANDONED:
+ case WAIT_OBJECT_0:
+ /* the object that we were waiting for has been destroyed (ABANDONED) or
+ * signalled (TIMEOUT_0). We can assume that the startup process is
+ * complete and tell the Service Control Manager that we are now runnng */
+ lutil_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
+ lutil_ServiceStatus.dwWin32ExitCode = NO_ERROR;
+ lutil_ServiceStatus.dwCheckPoint++;
+ lutil_ServiceStatus.dwWaitHint = 1000;
+ SetServiceStatus(hlutil_ServiceStatus, &lutil_ServiceStatus);
+ done = 1;
+ break;
+ case WAIT_TIMEOUT:
+ /* We've waited for the required time, so send an update to the Service Control
+ * Manager saying to wait again. */
+ lutil_ServiceStatus.dwCheckPoint++;
+ lutil_ServiceStatus.dwWaitHint = SCM_NOTIFICATION_INTERVAL * 2;
+ SetServiceStatus(hlutil_ServiceStatus, &lutil_ServiceStatus);
+ break;
+ case WAIT_FAILED:
+ /* theres been some problem with WaitForSingleObject so tell the Service
+ * Control Manager to wait 30 seconds before deploying its assasin and
+ * then leave the thread. */
+ lutil_ServiceStatus.dwCheckPoint++;
+ lutil_ServiceStatus.dwWaitHint = THIRTY_SECONDS;
+ SetServiceStatus(hlutil_ServiceStatus, &lutil_ServiceStatus);
+ done = 1;
+ break;
+ }
+ }
+ ldap_pvt_thread_exit(NULL);
+ return NULL;
+}
+
+
+
+static void *stop_status_routine( void *ptr )
+{
+ DWORD wait_result;
+ int done = 0;
+
+ while ( !done )
+ {
+ wait_result = WaitForSingleObject( stopped_event, SCM_NOTIFICATION_INTERVAL );
+ switch ( wait_result )
+ {
+ case WAIT_ABANDONED:
+ case WAIT_OBJECT_0:
+ /* the object that we were waiting for has been destroyed (ABANDONED) or
+ * signalled (TIMEOUT_0). The shutting down process is therefore complete
+ * and the final SERVICE_STOPPED message will be sent to the service control
+ * manager prior to the process terminating. */
+ done = 1;
+ break;
+ case WAIT_TIMEOUT:
+ /* We've waited for the required time, so send an update to the Service Control
+ * Manager saying to wait again. */
+ lutil_ServiceStatus.dwCheckPoint++;
+ lutil_ServiceStatus.dwWaitHint = SCM_NOTIFICATION_INTERVAL * 2;
+ SetServiceStatus(hlutil_ServiceStatus, &lutil_ServiceStatus);
+ break;
+ case WAIT_FAILED:
+ /* theres been some problem with WaitForSingleObject so tell the Service
+ * Control Manager to wait 30 seconds before deploying its assasin and
+ * then leave the thread. */
+ lutil_ServiceStatus.dwCheckPoint++;
+ lutil_ServiceStatus.dwWaitHint = THIRTY_SECONDS;
+ SetServiceStatus(hlutil_ServiceStatus, &lutil_ServiceStatus);
+ done = 1;
+ break;
+ }
+ }
+ ldap_pvt_thread_exit(NULL);
+ return NULL;
+}
+
+
+
+static void WINAPI lutil_ServiceCtrlHandler( IN DWORD Opcode)
+{
+ switch (Opcode)
+ {
+ case SERVICE_CONTROL_STOP:
+ case SERVICE_CONTROL_SHUTDOWN:
+
+ lutil_ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
+ lutil_ServiceStatus.dwCheckPoint++;
+ lutil_ServiceStatus.dwWaitHint = SCM_NOTIFICATION_INTERVAL * 2;
+ SetServiceStatus(hlutil_ServiceStatus, &lutil_ServiceStatus);
+
+ ldap_pvt_thread_cond_init( &stopped_event );
+ if ( stopped_event == NULL )
+ {
+ /* the event was not created. We will ask the service control manager for 30
+ * seconds to shutdown */
+ lutil_ServiceStatus.dwCheckPoint++;
+ lutil_ServiceStatus.dwWaitHint = THIRTY_SECONDS;
+ SetServiceStatus(hlutil_ServiceStatus, &lutil_ServiceStatus);
+ }
+ else
+ {
+ /* start a thread to report the progress to the service control manager
+ * until the stopped_event is fired. */
+ if ( ldap_pvt_thread_create( &stop_status_tid, 0, stop_status_routine, NULL ) == 0 )
+ {
+
+ }
+ else {
+ /* failed to create the thread that tells the Service Control Manager that the
+ * service stopping is proceeding.
+ * tell the Service Control Manager to wait another 30 seconds before deploying its
+ * assasin. */
+ lutil_ServiceStatus.dwCheckPoint++;
+ lutil_ServiceStatus.dwWaitHint = THIRTY_SECONDS;
+ SetServiceStatus(hlutil_ServiceStatus, &lutil_ServiceStatus);
+ }
+ }
+ stopfunc( -1 );
+ break;
+
+ case SERVICE_CONTROL_INTERROGATE:
+ SetServiceStatus(hlutil_ServiceStatus, &lutil_ServiceStatus);
+ break;
+ }
+ return;
+}
+
+void *lutil_getRegParam( char *svc, char *value )
+{
+ HKEY hkey;
+ char path[255];
+ DWORD vType;
+ static char vValue[1024];
+ DWORD valLen = sizeof( vValue );
+
+ if ( svc != NULL )
+ snprintf ( path, sizeof path, "SOFTWARE\\%s", svc );
+ else
+ snprintf ( path, sizeof path, "SOFTWARE\\OpenLDAP\\Parameters" );
+
+ if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, path, 0, KEY_READ, &hkey ) != ERROR_SUCCESS )
+ {
+ return NULL;
+ }
+
+ if ( RegQueryValueEx( hkey, value, NULL, &vType, vValue, &valLen ) != ERROR_SUCCESS )
+ {
+ RegCloseKey( hkey );
+ return NULL;
+ }
+ RegCloseKey( hkey );
+
+ switch ( vType )
+ {
+ case REG_BINARY:
+ case REG_DWORD:
+ return (void*)&vValue;
+ case REG_SZ:
+ return (void*)&vValue;
+ }
+ return (void*)NULL;
+}
+
+void lutil_LogStartedEvent( char *svc, int slap_debug, char *configfile, char *urls )
+{
+ char *Inserts[5];
+ WORD i = 0, j;
+ HANDLE hEventLog;
+
+ hEventLog = RegisterEventSource( NULL, svc );
+
+ Inserts[i] = (char *)malloc( 20 );
+ itoa( slap_debug, Inserts[i++], 10 );
+ Inserts[i++] = strdup( configfile );
+ Inserts[i++] = strdup( urls ? urls : "ldap:///" );
+
+ ReportEvent( hEventLog, EVENTLOG_INFORMATION_TYPE, 0,
+ MSG_SVC_STARTED, NULL, i, 0, (LPCSTR *) Inserts, NULL );
+
+ for ( j = 0; j < i; j++ )
+ ldap_memfree( Inserts[j] );
+ DeregisterEventSource( hEventLog );
+}
+
+
+
+void lutil_LogStoppedEvent( char *svc )
+{
+ HANDLE hEventLog;
+
+ hEventLog = RegisterEventSource( NULL, svc );
+ ReportEvent( hEventLog, EVENTLOG_INFORMATION_TYPE, 0,
+ MSG_SVC_STOPPED, NULL, 0, 0, NULL, NULL );
+ DeregisterEventSource( hEventLog );
+}
+
+
+void lutil_CommenceStartupProcessing( char *lpszServiceName,
+ void (*stopper)(int) )
+{
+ hlutil_ServiceStatus = RegisterServiceCtrlHandler( lpszServiceName, (LPHANDLER_FUNCTION)lutil_ServiceCtrlHandler);
+
+ stopfunc = stopper;
+
+ /* initialize the Service Status structure */
+ lutil_ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
+ lutil_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
+ lutil_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
+ lutil_ServiceStatus.dwWin32ExitCode = NO_ERROR;
+ lutil_ServiceStatus.dwServiceSpecificExitCode = 0;
+ lutil_ServiceStatus.dwCheckPoint = 1;
+ lutil_ServiceStatus.dwWaitHint = SCM_NOTIFICATION_INTERVAL * 2;
+
+ SetServiceStatus(hlutil_ServiceStatus, &lutil_ServiceStatus);
+
+ /* start up a thread to keep sending SERVICE_START_PENDING to the Service Control Manager
+ * until the slapd listener is completed and listening. Only then should we send
+ * SERVICE_RUNNING to the Service Control Manager. */
+ ldap_pvt_thread_cond_init( &started_event );
+ if ( started_event == NULL)
+ {
+ /* failed to create the event to determine when the startup process is complete so
+ * tell the Service Control Manager to wait another 30 seconds before deploying its
+ * assasin */
+ lutil_ServiceStatus.dwCheckPoint++;
+ lutil_ServiceStatus.dwWaitHint = THIRTY_SECONDS;
+ SetServiceStatus(hlutil_ServiceStatus, &lutil_ServiceStatus);
+ }
+ else
+ {
+ /* start a thread to report the progress to the service control manager
+ * until the started_event is fired. */
+ if ( ldap_pvt_thread_create( &start_status_tid, 0, start_status_routine, NULL ) == 0 )
+ {
+
+ }
+ else {
+ /* failed to create the thread that tells the Service Control Manager that the
+ * service startup is proceeding.
+ * tell the Service Control Manager to wait another 30 seconds before deploying its
+ * assasin. */
+ lutil_ServiceStatus.dwCheckPoint++;
+ lutil_ServiceStatus.dwWaitHint = THIRTY_SECONDS;
+ SetServiceStatus(hlutil_ServiceStatus, &lutil_ServiceStatus);
+ }
+ }
+}
+
+void lutil_ReportShutdownComplete( )
+{
+ if ( is_NT_Service )
+ {
+ /* stop sending SERVICE_STOP_PENDING messages to the Service Control Manager */
+ ldap_pvt_thread_cond_signal( &stopped_event );
+ ldap_pvt_thread_cond_destroy( &stopped_event );
+
+ /* wait for the thread sending the SERVICE_STOP_PENDING messages to the Service Control Manager to die.
+ * if the wait fails then put ourselves to sleep for half the Service Control Manager update interval */
+ if (ldap_pvt_thread_join( stop_status_tid, (void *) NULL ) == -1)
+ ldap_pvt_thread_sleep( SCM_NOTIFICATION_INTERVAL / 2 );
+
+ lutil_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
+ lutil_ServiceStatus.dwCheckPoint++;
+ lutil_ServiceStatus.dwWaitHint = SCM_NOTIFICATION_INTERVAL;
+ SetServiceStatus(hlutil_ServiceStatus, &lutil_ServiceStatus);
+ }
+}
+
+static char *GetErrorString( int err )
+{
+ static char msgBuf[1024];
+
+ FormatMessage(
+ FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ msgBuf, 1024, NULL );
+
+ return msgBuf;
+}
+
+static char *GetLastErrorString( void )
+{
+ return GetErrorString( GetLastError() );
+}
+#endif
diff --git a/libraries/liblutil/passfile.c b/libraries/liblutil/passfile.c
new file mode 100644
index 0000000..39ed708
--- /dev/null
+++ b/libraries/liblutil/passfile.c
@@ -0,0 +1,110 @@
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 1998-2018 The OpenLDAP Foundation.
+ * 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 the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/stdlib.h>
+#include <ac/ctype.h>
+#include <ac/string.h>
+
+#ifdef HAVE_FSTAT
+#include <sys/types.h>
+#include <sys/stat.h>
+#endif /* HAVE_FSTAT */
+
+#include <lber.h>
+#include <lutil.h>
+
+/* Get a password from a file. */
+int
+lutil_get_filed_password(
+ const char *filename,
+ struct berval *passwd )
+{
+ size_t nread, nleft, nr;
+ FILE *f = fopen( filename, "r" );
+
+ if( f == NULL ) {
+ perror( filename );
+ return -1;
+ }
+
+ passwd->bv_val = NULL;
+ passwd->bv_len = 4096;
+
+#ifdef HAVE_FSTAT
+ {
+ struct stat sb;
+ if ( fstat( fileno( f ), &sb ) == 0 ) {
+ if( sb.st_mode & 006 ) {
+ fprintf( stderr, _("Warning: Password file %s"
+ " is publicly readable/writeable\n"),
+ filename );
+ }
+
+ if ( sb.st_size )
+ passwd->bv_len = sb.st_size;
+ }
+ }
+#endif /* HAVE_FSTAT */
+
+ passwd->bv_val = (char *) ber_memalloc( passwd->bv_len + 1 );
+ if( passwd->bv_val == NULL ) {
+ perror( filename );
+ fclose( f );
+ return -1;
+ }
+
+ nread = 0;
+ nleft = passwd->bv_len;
+ do {
+ if( nleft == 0 ) {
+ /* double the buffer size */
+ char *p = (char *) ber_memrealloc( passwd->bv_val,
+ 2 * passwd->bv_len + 1 );
+ if( p == NULL ) {
+ ber_memfree( passwd->bv_val );
+ passwd->bv_val = NULL;
+ passwd->bv_len = 0;
+ fclose( f );
+ return -1;
+ }
+ nleft = passwd->bv_len;
+ passwd->bv_len *= 2;
+ passwd->bv_val = p;
+ }
+
+ nr = fread( &passwd->bv_val[nread], 1, nleft, f );
+
+ if( nr < nleft && ferror( f ) ) {
+ ber_memfree( passwd->bv_val );
+ passwd->bv_val = NULL;
+ passwd->bv_len = 0;
+ fclose( f );
+ return -1;
+ }
+
+ nread += nr;
+ nleft -= nr;
+ } while ( !feof(f) );
+
+ passwd->bv_len = nread;
+ passwd->bv_val[nread] = '\0';
+
+ fclose( f );
+ return 0;
+}
diff --git a/libraries/liblutil/passwd.c b/libraries/liblutil/passwd.c
new file mode 100644
index 0000000..e204ee4
--- /dev/null
+++ b/libraries/liblutil/passwd.c
@@ -0,0 +1,1263 @@
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 1998-2018 The OpenLDAP Foundation.
+ * 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 the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+
+/*
+ * int lutil_passwd(
+ * const struct berval *passwd,
+ * const struct berval *cred,
+ * const char **schemes )
+ *
+ * Returns true if user supplied credentials (cred) matches
+ * the stored password (passwd).
+ *
+ * Due to the use of the crypt(3) function
+ * this routine is NOT thread-safe.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+#include <ac/stdlib.h>
+#include <ac/string.h>
+#include <ac/unistd.h>
+
+#if defined(SLAPD_LMHASH)
+#if defined(HAVE_OPENSSL)
+# include <openssl/des.h>
+
+
+typedef DES_cblock des_key;
+typedef DES_cblock des_data_block;
+typedef DES_key_schedule des_context[1];
+#define des_failed(encrypted) 0
+#define des_finish(key, schedule)
+
+#elif defined(HAVE_MOZNSS)
+/*
+ hack hack hack
+ We need to define this here so that nspr/obsolete/protypes.h will not be included
+ if that file is included, it will create a uint32 typedef that will cause the
+ one in lutil_sha1.h to blow up
+*/
+#define PROTYPES_H 1
+# include <nss/pk11pub.h>
+typedef PK11SymKey *des_key;
+typedef unsigned char des_data_block[8];
+typedef PK11Context *des_context[1];
+#define DES_ENCRYPT CKA_ENCRYPT
+
+#endif
+
+#endif /* SLAPD_LMHASH */
+
+#include <ac/param.h>
+
+#ifdef SLAPD_CRYPT
+# include <ac/crypt.h>
+
+# if defined( HAVE_GETPWNAM ) && defined( HAVE_STRUCT_PASSWD_PW_PASSWD )
+# ifdef HAVE_SHADOW_H
+# include <shadow.h>
+# endif
+# ifdef HAVE_PWD_H
+# include <pwd.h>
+# endif
+# ifdef HAVE_AIX_SECURITY
+# include <userpw.h>
+# endif
+# endif
+#endif
+
+#include <lber.h>
+
+#include "ldap_pvt.h"
+#include "lber_pvt.h"
+
+#include "lutil_md5.h"
+#include "lutil_sha1.h"
+#include "lutil.h"
+
+static const unsigned char crypt64[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890./";
+
+#ifdef SLAPD_CRYPT
+static char *salt_format = NULL;
+static lutil_cryptfunc lutil_crypt;
+lutil_cryptfunc *lutil_cryptptr = lutil_crypt;
+#endif
+
+/* KLUDGE:
+ * chk_fn is NULL iff name is {CLEARTEXT}
+ * otherwise, things will break
+ */
+struct pw_scheme {
+ struct berval name;
+ LUTIL_PASSWD_CHK_FUNC *chk_fn;
+ LUTIL_PASSWD_HASH_FUNC *hash_fn;
+};
+
+struct pw_slist {
+ struct pw_slist *next;
+ struct pw_scheme s;
+};
+
+/* password check routines */
+
+#define SALT_SIZE 4
+
+static LUTIL_PASSWD_CHK_FUNC chk_md5;
+static LUTIL_PASSWD_CHK_FUNC chk_smd5;
+static LUTIL_PASSWD_HASH_FUNC hash_smd5;
+static LUTIL_PASSWD_HASH_FUNC hash_md5;
+
+
+#ifdef LUTIL_SHA1_BYTES
+static LUTIL_PASSWD_CHK_FUNC chk_ssha1;
+static LUTIL_PASSWD_CHK_FUNC chk_sha1;
+static LUTIL_PASSWD_HASH_FUNC hash_sha1;
+static LUTIL_PASSWD_HASH_FUNC hash_ssha1;
+#endif
+
+#ifdef SLAPD_LMHASH
+static LUTIL_PASSWD_CHK_FUNC chk_lanman;
+static LUTIL_PASSWD_HASH_FUNC hash_lanman;
+#endif
+
+#ifdef SLAPD_CRYPT
+static LUTIL_PASSWD_CHK_FUNC chk_crypt;
+static LUTIL_PASSWD_HASH_FUNC hash_crypt;
+
+#if defined( HAVE_GETPWNAM ) && defined( HAVE_STRUCT_PASSWD_PW_PASSWD )
+static LUTIL_PASSWD_CHK_FUNC chk_unix;
+#endif
+#endif
+
+/* password hash routines */
+
+#ifdef SLAPD_CLEARTEXT
+static LUTIL_PASSWD_HASH_FUNC hash_clear;
+#endif
+
+static struct pw_slist *pw_schemes;
+static int pw_inited;
+
+static const struct pw_scheme pw_schemes_default[] =
+{
+#ifdef LUTIL_SHA1_BYTES
+ { BER_BVC("{SSHA}"), chk_ssha1, hash_ssha1 },
+ { BER_BVC("{SHA}"), chk_sha1, hash_sha1 },
+#endif
+
+ { BER_BVC("{SMD5}"), chk_smd5, hash_smd5 },
+ { BER_BVC("{MD5}"), chk_md5, hash_md5 },
+
+#ifdef SLAPD_LMHASH
+ { BER_BVC("{LANMAN}"), chk_lanman, hash_lanman },
+#endif /* SLAPD_LMHASH */
+
+#ifdef SLAPD_CRYPT
+ { BER_BVC("{CRYPT}"), chk_crypt, hash_crypt },
+# if defined( HAVE_GETPWNAM ) && defined( HAVE_STRUCT_PASSWD_PW_PASSWD )
+ { BER_BVC("{UNIX}"), chk_unix, NULL },
+# endif
+#endif
+
+#ifdef SLAPD_CLEARTEXT
+ /* pseudo scheme */
+ { BER_BVC("{CLEARTEXT}"), NULL, hash_clear },
+#endif
+
+ { BER_BVNULL, NULL, NULL }
+};
+
+int lutil_passwd_add(
+ struct berval *scheme,
+ LUTIL_PASSWD_CHK_FUNC *chk,
+ LUTIL_PASSWD_HASH_FUNC *hash )
+{
+ struct pw_slist *ptr;
+
+ if (!pw_inited) lutil_passwd_init();
+
+ ptr = ber_memalloc( sizeof( struct pw_slist ));
+ if (!ptr) return -1;
+ ptr->next = pw_schemes;
+ ptr->s.name = *scheme;
+ ptr->s.chk_fn = chk;
+ ptr->s.hash_fn = hash;
+ pw_schemes = ptr;
+ return 0;
+}
+
+void lutil_passwd_init()
+{
+ struct pw_scheme *s;
+
+ pw_inited = 1;
+
+ for( s=(struct pw_scheme *)pw_schemes_default; s->name.bv_val; s++) {
+ if ( lutil_passwd_add( &s->name, s->chk_fn, s->hash_fn ) ) break;
+ }
+}
+
+void lutil_passwd_destroy()
+{
+ struct pw_slist *ptr, *next;
+
+ for( ptr=pw_schemes; ptr; ptr=next ) {
+ next = ptr->next;
+ ber_memfree( ptr );
+ }
+}
+
+static const struct pw_scheme *get_scheme(
+ const char* scheme )
+{
+ struct pw_slist *pws;
+ struct berval bv;
+
+ if (!pw_inited) lutil_passwd_init();
+
+ bv.bv_val = strchr( scheme, '}' );
+ if ( !bv.bv_val )
+ return NULL;
+
+ bv.bv_len = bv.bv_val - scheme + 1;
+ bv.bv_val = (char *) scheme;
+
+ for( pws=pw_schemes; pws; pws=pws->next ) {
+ if ( ber_bvstrcasecmp(&bv, &pws->s.name ) == 0 ) {
+ return &(pws->s);
+ }
+ }
+
+ return NULL;
+}
+
+int lutil_passwd_scheme(
+ const char* scheme )
+{
+ if( scheme == NULL ) {
+ return 0;
+ }
+
+ return get_scheme(scheme) != NULL;
+}
+
+
+static int is_allowed_scheme(
+ const char* scheme,
+ const char** schemes )
+{
+ int i;
+
+ if( schemes == NULL ) return 1;
+
+ for( i=0; schemes[i] != NULL; i++ ) {
+ if( strcasecmp( scheme, schemes[i] ) == 0 ) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static struct berval *passwd_scheme(
+ const struct pw_scheme *scheme,
+ const struct berval * passwd,
+ struct berval *bv,
+ const char** allowed )
+{
+ if( !is_allowed_scheme( scheme->name.bv_val, allowed ) ) {
+ return NULL;
+ }
+
+ if( passwd->bv_len >= scheme->name.bv_len ) {
+ if( strncasecmp( passwd->bv_val, scheme->name.bv_val, scheme->name.bv_len ) == 0 ) {
+ bv->bv_val = &passwd->bv_val[scheme->name.bv_len];
+ bv->bv_len = passwd->bv_len - scheme->name.bv_len;
+
+ return bv;
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * Return 0 if creds are good.
+ */
+int
+lutil_passwd(
+ const struct berval *passwd, /* stored passwd */
+ const struct berval *cred, /* user cred */
+ const char **schemes,
+ const char **text )
+{
+ struct pw_slist *pws;
+
+ if ( text ) *text = NULL;
+
+ if (cred == NULL || cred->bv_len == 0 ||
+ passwd == NULL || passwd->bv_len == 0 )
+ {
+ return -1;
+ }
+
+ if (!pw_inited) lutil_passwd_init();
+
+ for( pws=pw_schemes; pws; pws=pws->next ) {
+ if( pws->s.chk_fn ) {
+ struct berval x;
+ struct berval *p = passwd_scheme( &(pws->s),
+ passwd, &x, schemes );
+
+ if( p != NULL ) {
+ return (pws->s.chk_fn)( &(pws->s.name), p, cred, text );
+ }
+ }
+ }
+
+#ifdef SLAPD_CLEARTEXT
+ /* Do we think there is a scheme specifier here that we
+ * didn't recognize? Assume a scheme name is at least 1 character.
+ */
+ if (( passwd->bv_val[0] == '{' ) &&
+ ( ber_bvchr( passwd, '}' ) > passwd->bv_val+1 ))
+ {
+ return 1;
+ }
+ if( is_allowed_scheme("{CLEARTEXT}", schemes ) ) {
+ return ( passwd->bv_len == cred->bv_len ) ?
+ memcmp( passwd->bv_val, cred->bv_val, passwd->bv_len )
+ : 1;
+ }
+#endif
+ return 1;
+}
+
+int lutil_passwd_generate( struct berval *pw, ber_len_t len )
+{
+
+ if( len < 1 ) return -1;
+
+ pw->bv_len = len;
+ pw->bv_val = ber_memalloc( len + 1 );
+
+ if( pw->bv_val == NULL ) {
+ return -1;
+ }
+
+ if( lutil_entropy( (unsigned char *) pw->bv_val, pw->bv_len) < 0 ) {
+ return -1;
+ }
+
+ for( len = 0; len < pw->bv_len; len++ ) {
+ pw->bv_val[len] = crypt64[
+ pw->bv_val[len] % (sizeof(crypt64)-1) ];
+ }
+
+ pw->bv_val[len] = '\0';
+
+ return 0;
+}
+
+int lutil_passwd_hash(
+ const struct berval * passwd,
+ const char * method,
+ struct berval *hash,
+ const char **text )
+{
+ const struct pw_scheme *sc = get_scheme( method );
+
+ hash->bv_val = NULL;
+ hash->bv_len = 0;
+
+ if( sc == NULL ) {
+ if( text ) *text = "scheme not recognized";
+ return -1;
+ }
+
+ if( ! sc->hash_fn ) {
+ if( text ) *text = "scheme provided no hash function";
+ return -1;
+ }
+
+ if( text ) *text = NULL;
+
+ return (sc->hash_fn)( &sc->name, passwd, hash, text );
+}
+
+/* pw_string is only called when SLAPD_LMHASH or SLAPD_CRYPT is defined */
+#if defined(SLAPD_LMHASH) || defined(SLAPD_CRYPT)
+static int pw_string(
+ const struct berval *sc,
+ struct berval *passwd )
+{
+ struct berval pw;
+
+ pw.bv_len = sc->bv_len + passwd->bv_len;
+ pw.bv_val = ber_memalloc( pw.bv_len + 1 );
+
+ if( pw.bv_val == NULL ) {
+ return LUTIL_PASSWD_ERR;
+ }
+
+ AC_MEMCPY( pw.bv_val, sc->bv_val, sc->bv_len );
+ AC_MEMCPY( &pw.bv_val[sc->bv_len], passwd->bv_val, passwd->bv_len );
+
+ pw.bv_val[pw.bv_len] = '\0';
+ *passwd = pw;
+
+ return LUTIL_PASSWD_OK;
+}
+#endif /* SLAPD_LMHASH || SLAPD_CRYPT */
+
+int lutil_passwd_string64(
+ const struct berval *sc,
+ const struct berval *hash,
+ struct berval *b64,
+ const struct berval *salt )
+{
+ int rc;
+ struct berval string;
+ size_t b64len;
+
+ if( salt ) {
+ /* need to base64 combined string */
+ string.bv_len = hash->bv_len + salt->bv_len;
+ string.bv_val = ber_memalloc( string.bv_len + 1 );
+
+ if( string.bv_val == NULL ) {
+ return LUTIL_PASSWD_ERR;
+ }
+
+ AC_MEMCPY( string.bv_val, hash->bv_val,
+ hash->bv_len );
+ AC_MEMCPY( &string.bv_val[hash->bv_len], salt->bv_val,
+ salt->bv_len );
+ string.bv_val[string.bv_len] = '\0';
+
+ } else {
+ string = *hash;
+ }
+
+ b64len = LUTIL_BASE64_ENCODE_LEN( string.bv_len ) + 1;
+ b64->bv_len = b64len + sc->bv_len;
+ b64->bv_val = ber_memalloc( b64->bv_len + 1 );
+
+ if( b64->bv_val == NULL ) {
+ if( salt ) ber_memfree( string.bv_val );
+ return LUTIL_PASSWD_ERR;
+ }
+
+ AC_MEMCPY(b64->bv_val, sc->bv_val, sc->bv_len);
+
+ rc = lutil_b64_ntop(
+ (unsigned char *) string.bv_val, string.bv_len,
+ &b64->bv_val[sc->bv_len], b64len );
+
+ if( salt ) ber_memfree( string.bv_val );
+
+ if( rc < 0 ) {
+ return LUTIL_PASSWD_ERR;
+ }
+
+ /* recompute length */
+ b64->bv_len = sc->bv_len + rc;
+ assert( strlen(b64->bv_val) == b64->bv_len );
+ return LUTIL_PASSWD_OK;
+}
+
+/* PASSWORD CHECK ROUTINES */
+
+#ifdef LUTIL_SHA1_BYTES
+static int chk_ssha1(
+ const struct berval *sc,
+ const struct berval * passwd,
+ const struct berval * cred,
+ const char **text )
+{
+ lutil_SHA1_CTX SHA1context;
+ unsigned char SHA1digest[LUTIL_SHA1_BYTES];
+ int rc;
+ unsigned char *orig_pass = NULL;
+ size_t decode_len = LUTIL_BASE64_DECODE_LEN(passwd->bv_len);
+
+ /* safety check -- must have some salt */
+ if (decode_len <= sizeof(SHA1digest)) {
+ return LUTIL_PASSWD_ERR;
+ }
+
+ /* decode base64 password */
+ orig_pass = (unsigned char *) ber_memalloc(decode_len + 1);
+
+ if( orig_pass == NULL ) return LUTIL_PASSWD_ERR;
+
+ rc = lutil_b64_pton(passwd->bv_val, orig_pass, decode_len);
+
+ /* safety check -- must have some salt */
+ if (rc <= (int)(sizeof(SHA1digest))) {
+ ber_memfree(orig_pass);
+ return LUTIL_PASSWD_ERR;
+ }
+
+ /* hash credentials with salt */
+ lutil_SHA1Init(&SHA1context);
+ lutil_SHA1Update(&SHA1context,
+ (const unsigned char *) cred->bv_val, cred->bv_len);
+ lutil_SHA1Update(&SHA1context,
+ (const unsigned char *) &orig_pass[sizeof(SHA1digest)],
+ rc - sizeof(SHA1digest));
+ lutil_SHA1Final(SHA1digest, &SHA1context);
+
+ /* compare */
+ rc = memcmp((char *)orig_pass, (char *)SHA1digest, sizeof(SHA1digest));
+ ber_memfree(orig_pass);
+ return rc ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK;
+}
+
+static int chk_sha1(
+ const struct berval *sc,
+ const struct berval * passwd,
+ const struct berval * cred,
+ const char **text )
+{
+ lutil_SHA1_CTX SHA1context;
+ unsigned char SHA1digest[LUTIL_SHA1_BYTES];
+ int rc;
+ unsigned char *orig_pass = NULL;
+ size_t decode_len = LUTIL_BASE64_DECODE_LEN(passwd->bv_len);
+
+ /* safety check */
+ if (decode_len < sizeof(SHA1digest)) {
+ return LUTIL_PASSWD_ERR;
+ }
+
+ /* base64 un-encode password */
+ orig_pass = (unsigned char *) ber_memalloc(decode_len + 1);
+
+ if( orig_pass == NULL ) return LUTIL_PASSWD_ERR;
+
+ rc = lutil_b64_pton(passwd->bv_val, orig_pass, decode_len);
+
+ if( rc != sizeof(SHA1digest) ) {
+ ber_memfree(orig_pass);
+ return LUTIL_PASSWD_ERR;
+ }
+
+ /* hash credentials with salt */
+ lutil_SHA1Init(&SHA1context);
+ lutil_SHA1Update(&SHA1context,
+ (const unsigned char *) cred->bv_val, cred->bv_len);
+ lutil_SHA1Final(SHA1digest, &SHA1context);
+
+ /* compare */
+ rc = memcmp((char *)orig_pass, (char *)SHA1digest, sizeof(SHA1digest));
+ ber_memfree(orig_pass);
+ return rc ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK;
+}
+#endif
+
+static int chk_smd5(
+ const struct berval *sc,
+ const struct berval * passwd,
+ const struct berval * cred,
+ const char **text )
+{
+ lutil_MD5_CTX MD5context;
+ unsigned char MD5digest[LUTIL_MD5_BYTES];
+ int rc;
+ unsigned char *orig_pass = NULL;
+ size_t decode_len = LUTIL_BASE64_DECODE_LEN(passwd->bv_len);
+
+ /* safety check */
+ if (decode_len <= sizeof(MD5digest)) {
+ return LUTIL_PASSWD_ERR;
+ }
+
+ /* base64 un-encode password */
+ orig_pass = (unsigned char *) ber_memalloc(decode_len + 1);
+
+ if( orig_pass == NULL ) return LUTIL_PASSWD_ERR;
+
+ rc = lutil_b64_pton(passwd->bv_val, orig_pass, decode_len);
+
+ if (rc <= (int)(sizeof(MD5digest))) {
+ ber_memfree(orig_pass);
+ return LUTIL_PASSWD_ERR;
+ }
+
+ /* hash credentials with salt */
+ lutil_MD5Init(&MD5context);
+ lutil_MD5Update(&MD5context,
+ (const unsigned char *) cred->bv_val,
+ cred->bv_len );
+ lutil_MD5Update(&MD5context,
+ &orig_pass[sizeof(MD5digest)],
+ rc - sizeof(MD5digest));
+ lutil_MD5Final(MD5digest, &MD5context);
+
+ /* compare */
+ rc = memcmp((char *)orig_pass, (char *)MD5digest, sizeof(MD5digest));
+ ber_memfree(orig_pass);
+ return rc ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK;
+}
+
+static int chk_md5(
+ const struct berval *sc,
+ const struct berval * passwd,
+ const struct berval * cred,
+ const char **text )
+{
+ lutil_MD5_CTX MD5context;
+ unsigned char MD5digest[LUTIL_MD5_BYTES];
+ int rc;
+ unsigned char *orig_pass = NULL;
+ size_t decode_len = LUTIL_BASE64_DECODE_LEN(passwd->bv_len);
+
+ /* safety check */
+ if (decode_len < sizeof(MD5digest)) {
+ return LUTIL_PASSWD_ERR;
+ }
+
+ /* base64 un-encode password */
+ orig_pass = (unsigned char *) ber_memalloc(decode_len + 1);
+
+ if( orig_pass == NULL ) return LUTIL_PASSWD_ERR;
+
+ rc = lutil_b64_pton(passwd->bv_val, orig_pass, decode_len);
+ if ( rc != sizeof(MD5digest) ) {
+ ber_memfree(orig_pass);
+ return LUTIL_PASSWD_ERR;
+ }
+
+ /* hash credentials with salt */
+ lutil_MD5Init(&MD5context);
+ lutil_MD5Update(&MD5context,
+ (const unsigned char *) cred->bv_val,
+ cred->bv_len );
+ lutil_MD5Final(MD5digest, &MD5context);
+
+ /* compare */
+ rc = memcmp((char *)orig_pass, (char *)MD5digest, sizeof(MD5digest));
+ ber_memfree(orig_pass);
+ return rc ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK;
+}
+
+#ifdef SLAPD_LMHASH
+
+#if defined(HAVE_OPENSSL)
+
+/*
+ * abstract away setting the parity.
+ */
+static void
+des_set_key_and_parity( des_key *key, unsigned char *keyData)
+{
+ memcpy(key, keyData, 8);
+ DES_set_odd_parity( key );
+}
+
+
+#elif defined(HAVE_MOZNSS)
+
+/*
+ * implement MozNSS wrappers for the openSSL calls
+ */
+static void
+des_set_key_and_parity( des_key *key, unsigned char *keyData)
+{
+ SECItem keyDataItem;
+ PK11SlotInfo *slot;
+ *key = NULL;
+
+ keyDataItem.data = keyData;
+ keyDataItem.len = 8;
+
+ slot = PK11_GetBestSlot(CKM_DES_ECB, NULL);
+ if (slot == NULL) {
+ return;
+ }
+
+ /* NOTE: this will not work in FIPS mode. In order to make lmhash
+ * work in fips mode we need to define a LMHASH pbe mechanism and
+ * do the fulll key derivation inside the token */
+ *key = PK11_ImportSymKey(slot, CKM_DES_ECB, PK11_OriginGenerated,
+ CKA_ENCRYPT, &keyDataItem, NULL);
+}
+
+static void
+DES_set_key_unchecked( des_key *key, des_context ctxt )
+{
+ ctxt[0] = NULL;
+
+ /* handle error conditions from previous call */
+ if (!*key) {
+ return;
+ }
+
+ ctxt[0] = PK11_CreateContextBySymKey(CKM_DES_ECB, CKA_ENCRYPT, *key, NULL);
+}
+
+static void
+DES_ecb_encrypt( des_data_block *plain, des_data_block *encrypted,
+ des_context ctxt, int op)
+{
+ SECStatus rv;
+ int size;
+
+ if (ctxt[0] == NULL) {
+ /* need to fail here... */
+ memset(encrypted, 0, sizeof(des_data_block));
+ return;
+ }
+ rv = PK11_CipherOp(ctxt[0], (unsigned char *)&encrypted[0],
+ &size, sizeof(des_data_block),
+ (unsigned char *)&plain[0], sizeof(des_data_block));
+ if (rv != SECSuccess) {
+ /* signal failure */
+ memset(encrypted, 0, sizeof(des_data_block));
+ return;
+ }
+ return;
+}
+
+static int
+des_failed(des_data_block *encrypted)
+{
+ static const des_data_block zero = { 0 };
+ return memcmp(encrypted, zero, sizeof(zero)) == 0;
+}
+
+static void
+des_finish(des_key *key, des_context ctxt)
+{
+ if (*key) {
+ PK11_FreeSymKey(*key);
+ *key = NULL;
+ }
+ if (ctxt[0]) {
+ PK11_Finalize(ctxt[0]);
+ PK11_DestroyContext(ctxt[0], PR_TRUE);
+ ctxt[0] = NULL;
+ }
+}
+
+#endif
+
+/* pseudocode from RFC2433
+ * A.2 LmPasswordHash()
+ *
+ * LmPasswordHash(
+ * IN 0-to-14-oem-char Password,
+ * OUT 16-octet PasswordHash )
+ * {
+ * Set UcasePassword to the uppercased Password
+ * Zero pad UcasePassword to 14 characters
+ *
+ * DesHash( 1st 7-octets of UcasePassword,
+ * giving 1st 8-octets of PasswordHash )
+ *
+ * DesHash( 2nd 7-octets of UcasePassword,
+ * giving 2nd 8-octets of PasswordHash )
+ * }
+ *
+ *
+ * A.3 DesHash()
+ *
+ * DesHash(
+ * IN 7-octet Clear,
+ * OUT 8-octet Cypher )
+ * {
+ * *
+ * * Make Cypher an irreversibly encrypted form of Clear by
+ * * encrypting known text using Clear as the secret key.
+ * * The known text consists of the string
+ * *
+ * * KGS!@#$%
+ * *
+ *
+ * Set StdText to "KGS!@#$%"
+ * DesEncrypt( StdText, Clear, giving Cypher )
+ * }
+ *
+ *
+ * A.4 DesEncrypt()
+ *
+ * DesEncrypt(
+ * IN 8-octet Clear,
+ * IN 7-octet Key,
+ * OUT 8-octet Cypher )
+ * {
+ * *
+ * * Use the DES encryption algorithm [4] in ECB mode [9]
+ * * to encrypt Clear into Cypher such that Cypher can
+ * * only be decrypted back to Clear by providing Key.
+ * * Note that the DES algorithm takes as input a 64-bit
+ * * stream where the 8th, 16th, 24th, etc. bits are
+ * * parity bits ignored by the encrypting algorithm.
+ * * Unless you write your own DES to accept 56-bit input
+ * * without parity, you will need to insert the parity bits
+ * * yourself.
+ * *
+ * }
+ */
+
+static void lmPasswd_to_key(
+ const char *lmPasswd,
+ des_key *key)
+{
+ const unsigned char *lpw = (const unsigned char *) lmPasswd;
+ unsigned char k[8];
+
+ /* make room for parity bits */
+ k[0] = lpw[0];
+ k[1] = ((lpw[0] & 0x01) << 7) | (lpw[1] >> 1);
+ k[2] = ((lpw[1] & 0x03) << 6) | (lpw[2] >> 2);
+ k[3] = ((lpw[2] & 0x07) << 5) | (lpw[3] >> 3);
+ k[4] = ((lpw[3] & 0x0F) << 4) | (lpw[4] >> 4);
+ k[5] = ((lpw[4] & 0x1F) << 3) | (lpw[5] >> 5);
+ k[6] = ((lpw[5] & 0x3F) << 2) | (lpw[6] >> 6);
+ k[7] = ((lpw[6] & 0x7F) << 1);
+
+ des_set_key_and_parity( key, k );
+}
+
+static int chk_lanman(
+ const struct berval *scheme,
+ const struct berval *passwd,
+ const struct berval *cred,
+ const char **text )
+{
+ ber_len_t i;
+ char UcasePassword[15];
+ des_key key;
+ des_context schedule;
+ des_data_block StdText = "KGS!@#$%";
+ des_data_block PasswordHash1, PasswordHash2;
+ char PasswordHash[33], storedPasswordHash[33];
+
+ for( i=0; i<cred->bv_len; i++) {
+ if(cred->bv_val[i] == '\0') {
+ return LUTIL_PASSWD_ERR; /* NUL character in password */
+ }
+ }
+
+ if( cred->bv_val[i] != '\0' ) {
+ return LUTIL_PASSWD_ERR; /* passwd must behave like a string */
+ }
+
+ strncpy( UcasePassword, cred->bv_val, 14 );
+ UcasePassword[14] = '\0';
+ ldap_pvt_str2upper( UcasePassword );
+
+ lmPasswd_to_key( UcasePassword, &key );
+ DES_set_key_unchecked( &key, schedule );
+ DES_ecb_encrypt( &StdText, &PasswordHash1, schedule , DES_ENCRYPT );
+
+ if (des_failed(&PasswordHash1)) {
+ return LUTIL_PASSWD_ERR;
+ }
+
+ lmPasswd_to_key( &UcasePassword[7], &key );
+ DES_set_key_unchecked( &key, schedule );
+ DES_ecb_encrypt( &StdText, &PasswordHash2, schedule , DES_ENCRYPT );
+ if (des_failed(&PasswordHash2)) {
+ return LUTIL_PASSWD_ERR;
+ }
+
+ des_finish( &key, schedule );
+
+ sprintf( PasswordHash, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
+ PasswordHash1[0],PasswordHash1[1],PasswordHash1[2],PasswordHash1[3],
+ PasswordHash1[4],PasswordHash1[5],PasswordHash1[6],PasswordHash1[7],
+ PasswordHash2[0],PasswordHash2[1],PasswordHash2[2],PasswordHash2[3],
+ PasswordHash2[4],PasswordHash2[5],PasswordHash2[6],PasswordHash2[7] );
+
+ /* as a precaution convert stored password hash to lower case */
+ strncpy( storedPasswordHash, passwd->bv_val, 32 );
+ storedPasswordHash[32] = '\0';
+ ldap_pvt_str2lower( storedPasswordHash );
+
+ return memcmp( PasswordHash, storedPasswordHash, 32) ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK;
+}
+#endif /* SLAPD_LMHASH */
+
+#ifdef SLAPD_CRYPT
+static int lutil_crypt(
+ const char *key,
+ const char *salt,
+ char **hash )
+{
+ char *cr = crypt( key, salt );
+ int rc;
+
+ if( cr == NULL || cr[0] == '\0' ) {
+ /* salt must have been invalid */
+ rc = LUTIL_PASSWD_ERR;
+ } else {
+ if ( hash ) {
+ *hash = ber_strdup( cr );
+ rc = LUTIL_PASSWD_OK;
+ } else {
+ rc = strcmp( salt, cr ) ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK;
+ }
+ }
+ return rc;
+}
+
+static int chk_crypt(
+ const struct berval *sc,
+ const struct berval * passwd,
+ const struct berval * cred,
+ const char **text )
+{
+ unsigned int i;
+
+ for( i=0; i<cred->bv_len; i++) {
+ if(cred->bv_val[i] == '\0') {
+ return LUTIL_PASSWD_ERR; /* NUL character in password */
+ }
+ }
+
+ if( cred->bv_val[i] != '\0' ) {
+ return LUTIL_PASSWD_ERR; /* cred must behave like a string */
+ }
+
+ if( passwd->bv_len < 2 ) {
+ return LUTIL_PASSWD_ERR; /* passwd must be at least two characters long */
+ }
+
+ for( i=0; i<passwd->bv_len; i++) {
+ if(passwd->bv_val[i] == '\0') {
+ return LUTIL_PASSWD_ERR; /* NUL character in password */
+ }
+ }
+
+ if( passwd->bv_val[i] != '\0' ) {
+ return LUTIL_PASSWD_ERR; /* passwd must behave like a string */
+ }
+
+ return lutil_cryptptr( cred->bv_val, passwd->bv_val, NULL );
+}
+
+# if defined( HAVE_GETPWNAM ) && defined( HAVE_STRUCT_PASSWD_PW_PASSWD )
+static int chk_unix(
+ const struct berval *sc,
+ const struct berval * passwd,
+ const struct berval * cred,
+ const char **text )
+{
+ unsigned int i;
+ char *pw;
+
+ for( i=0; i<cred->bv_len; i++) {
+ if(cred->bv_val[i] == '\0') {
+ return LUTIL_PASSWD_ERR; /* NUL character in password */
+ }
+ }
+ if( cred->bv_val[i] != '\0' ) {
+ return LUTIL_PASSWD_ERR; /* cred must behave like a string */
+ }
+
+ for( i=0; i<passwd->bv_len; i++) {
+ if(passwd->bv_val[i] == '\0') {
+ return LUTIL_PASSWD_ERR; /* NUL character in password */
+ }
+ }
+
+ if( passwd->bv_val[i] != '\0' ) {
+ return LUTIL_PASSWD_ERR; /* passwd must behave like a string */
+ }
+
+ {
+ struct passwd *pwd = getpwnam(passwd->bv_val);
+
+ if(pwd == NULL) {
+ return LUTIL_PASSWD_ERR; /* not found */
+ }
+
+ pw = pwd->pw_passwd;
+ }
+# ifdef HAVE_GETSPNAM
+ {
+ struct spwd *spwd = getspnam(passwd->bv_val);
+
+ if(spwd != NULL) {
+ pw = spwd->sp_pwdp;
+ }
+ }
+# endif
+# ifdef HAVE_AIX_SECURITY
+ {
+ struct userpw *upw = getuserpw(passwd->bv_val);
+
+ if (upw != NULL) {
+ pw = upw->upw_passwd;
+ }
+ }
+# endif
+
+ if( pw == NULL || pw[0] == '\0' || pw[1] == '\0' ) {
+ /* password must must be at least two characters long */
+ return LUTIL_PASSWD_ERR;
+ }
+
+ return lutil_cryptptr( cred->bv_val, pw, NULL );
+}
+# endif
+#endif
+
+/* PASSWORD GENERATION ROUTINES */
+
+#ifdef LUTIL_SHA1_BYTES
+static int hash_ssha1(
+ const struct berval *scheme,
+ const struct berval *passwd,
+ struct berval *hash,
+ const char **text )
+{
+ lutil_SHA1_CTX SHA1context;
+ unsigned char SHA1digest[LUTIL_SHA1_BYTES];
+ char saltdata[SALT_SIZE];
+ struct berval digest;
+ struct berval salt;
+
+ digest.bv_val = (char *) SHA1digest;
+ digest.bv_len = sizeof(SHA1digest);
+ salt.bv_val = saltdata;
+ salt.bv_len = sizeof(saltdata);
+
+ if( lutil_entropy( (unsigned char *) salt.bv_val, salt.bv_len) < 0 ) {
+ return LUTIL_PASSWD_ERR;
+ }
+
+ lutil_SHA1Init( &SHA1context );
+ lutil_SHA1Update( &SHA1context,
+ (const unsigned char *)passwd->bv_val, passwd->bv_len );
+ lutil_SHA1Update( &SHA1context,
+ (const unsigned char *)salt.bv_val, salt.bv_len );
+ lutil_SHA1Final( SHA1digest, &SHA1context );
+
+ return lutil_passwd_string64( scheme, &digest, hash, &salt);
+}
+
+static int hash_sha1(
+ const struct berval *scheme,
+ const struct berval *passwd,
+ struct berval *hash,
+ const char **text )
+{
+ lutil_SHA1_CTX SHA1context;
+ unsigned char SHA1digest[LUTIL_SHA1_BYTES];
+ struct berval digest;
+ digest.bv_val = (char *) SHA1digest;
+ digest.bv_len = sizeof(SHA1digest);
+
+ lutil_SHA1Init( &SHA1context );
+ lutil_SHA1Update( &SHA1context,
+ (const unsigned char *)passwd->bv_val, passwd->bv_len );
+ lutil_SHA1Final( SHA1digest, &SHA1context );
+
+ return lutil_passwd_string64( scheme, &digest, hash, NULL);
+}
+#endif
+
+static int hash_smd5(
+ const struct berval *scheme,
+ const struct berval *passwd,
+ struct berval *hash,
+ const char **text )
+{
+ lutil_MD5_CTX MD5context;
+ unsigned char MD5digest[LUTIL_MD5_BYTES];
+ char saltdata[SALT_SIZE];
+ struct berval digest;
+ struct berval salt;
+
+ digest.bv_val = (char *) MD5digest;
+ digest.bv_len = sizeof(MD5digest);
+ salt.bv_val = saltdata;
+ salt.bv_len = sizeof(saltdata);
+
+ if( lutil_entropy( (unsigned char *) salt.bv_val, salt.bv_len) < 0 ) {
+ return LUTIL_PASSWD_ERR;
+ }
+
+ lutil_MD5Init( &MD5context );
+ lutil_MD5Update( &MD5context,
+ (const unsigned char *) passwd->bv_val, passwd->bv_len );
+ lutil_MD5Update( &MD5context,
+ (const unsigned char *) salt.bv_val, salt.bv_len );
+ lutil_MD5Final( MD5digest, &MD5context );
+
+ return lutil_passwd_string64( scheme, &digest, hash, &salt );
+}
+
+static int hash_md5(
+ const struct berval *scheme,
+ const struct berval *passwd,
+ struct berval *hash,
+ const char **text )
+{
+ lutil_MD5_CTX MD5context;
+ unsigned char MD5digest[LUTIL_MD5_BYTES];
+
+ struct berval digest;
+
+ digest.bv_val = (char *) MD5digest;
+ digest.bv_len = sizeof(MD5digest);
+
+ lutil_MD5Init( &MD5context );
+ lutil_MD5Update( &MD5context,
+ (const unsigned char *) passwd->bv_val, passwd->bv_len );
+ lutil_MD5Final( MD5digest, &MD5context );
+
+ return lutil_passwd_string64( scheme, &digest, hash, NULL );
+;
+}
+
+#ifdef SLAPD_LMHASH
+static int hash_lanman(
+ const struct berval *scheme,
+ const struct berval *passwd,
+ struct berval *hash,
+ const char **text )
+{
+
+ ber_len_t i;
+ char UcasePassword[15];
+ des_key key;
+ des_context schedule;
+ des_data_block StdText = "KGS!@#$%";
+ des_data_block PasswordHash1, PasswordHash2;
+ char PasswordHash[33];
+
+ for( i=0; i<passwd->bv_len; i++) {
+ if(passwd->bv_val[i] == '\0') {
+ return LUTIL_PASSWD_ERR; /* NUL character in password */
+ }
+ }
+
+ if( passwd->bv_val[i] != '\0' ) {
+ return LUTIL_PASSWD_ERR; /* passwd must behave like a string */
+ }
+
+ strncpy( UcasePassword, passwd->bv_val, 14 );
+ UcasePassword[14] = '\0';
+ ldap_pvt_str2upper( UcasePassword );
+
+ lmPasswd_to_key( UcasePassword, &key );
+ DES_set_key_unchecked( &key, schedule );
+ DES_ecb_encrypt( &StdText, &PasswordHash1, schedule , DES_ENCRYPT );
+
+ lmPasswd_to_key( &UcasePassword[7], &key );
+ DES_set_key_unchecked( &key, schedule );
+ DES_ecb_encrypt( &StdText, &PasswordHash2, schedule , DES_ENCRYPT );
+
+ sprintf( PasswordHash, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
+ PasswordHash1[0],PasswordHash1[1],PasswordHash1[2],PasswordHash1[3],
+ PasswordHash1[4],PasswordHash1[5],PasswordHash1[6],PasswordHash1[7],
+ PasswordHash2[0],PasswordHash2[1],PasswordHash2[2],PasswordHash2[3],
+ PasswordHash2[4],PasswordHash2[5],PasswordHash2[6],PasswordHash2[7] );
+
+ hash->bv_val = PasswordHash;
+ hash->bv_len = 32;
+
+ return pw_string( scheme, hash );
+}
+#endif /* SLAPD_LMHASH */
+
+#ifdef SLAPD_CRYPT
+static int hash_crypt(
+ const struct berval *scheme,
+ const struct berval *passwd,
+ struct berval *hash,
+ const char **text )
+{
+ unsigned char salt[32]; /* salt suitable for most anything */
+ unsigned int i;
+ char *save;
+ int rc;
+
+ for( i=0; i<passwd->bv_len; i++) {
+ if(passwd->bv_val[i] == '\0') {
+ return LUTIL_PASSWD_ERR; /* NUL character in password */
+ }
+ }
+
+ if( passwd->bv_val[i] != '\0' ) {
+ return LUTIL_PASSWD_ERR; /* passwd must behave like a string */
+ }
+
+ if( lutil_entropy( salt, sizeof( salt ) ) < 0 ) {
+ return LUTIL_PASSWD_ERR;
+ }
+
+ for( i=0; i< ( sizeof(salt) - 1 ); i++ ) {
+ salt[i] = crypt64[ salt[i] % (sizeof(crypt64)-1) ];
+ }
+ salt[sizeof( salt ) - 1 ] = '\0';
+
+ if( salt_format != NULL ) {
+ /* copy the salt we made into entropy before snprintfing
+ it back into the salt */
+ char entropy[sizeof(salt)];
+ strcpy( entropy, (char *) salt );
+ snprintf( (char *) salt, sizeof(entropy), salt_format, entropy );
+ }
+
+ rc = lutil_cryptptr( passwd->bv_val, (char *) salt, &hash->bv_val );
+ if ( rc != LUTIL_PASSWD_OK ) return rc;
+
+ if( hash->bv_val == NULL ) return -1;
+
+ hash->bv_len = strlen( hash->bv_val );
+
+ save = hash->bv_val;
+
+ if( hash->bv_len == 0 ) {
+ rc = LUTIL_PASSWD_ERR;
+ } else {
+ rc = pw_string( scheme, hash );
+ }
+ ber_memfree( save );
+ return rc;
+}
+#endif
+
+int lutil_salt_format(const char *format)
+{
+#ifdef SLAPD_CRYPT
+ ber_memfree( salt_format );
+
+ salt_format = format != NULL ? ber_strdup( format ) : NULL;
+#endif
+
+ return 0;
+}
+
+#ifdef SLAPD_CLEARTEXT
+static int hash_clear(
+ const struct berval *scheme,
+ const struct berval *passwd,
+ struct berval *hash,
+ const char **text )
+{
+ ber_dupbv( hash, (struct berval *)passwd );
+ return LUTIL_PASSWD_OK;
+}
+#endif
+
diff --git a/libraries/liblutil/ptest.c b/libraries/liblutil/ptest.c
new file mode 100644
index 0000000..3f806ec
--- /dev/null
+++ b/libraries/liblutil/ptest.c
@@ -0,0 +1,112 @@
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 1998-2018 The OpenLDAP Foundation.
+ * 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 the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/stdlib.h>
+
+#include <ac/ctype.h>
+#include <ac/signal.h>
+#include <ac/socket.h>
+#include <ac/string.h>
+#include <ac/time.h>
+
+#include <lber.h>
+
+#include "lutil.h"
+
+/*
+ * Password Test Program
+ */
+
+static char *hash[] = {
+#ifdef SLAP_AUTHPASSWD
+ "SHA1", "MD5",
+#else
+#ifdef SLAPD_CRYPT
+ "{CRYPT}",
+#endif
+ "{SSHA}", "{SMD5}",
+ "{SHA}", "{MD5}",
+ "{BOGUS}",
+#endif
+ NULL
+};
+
+static struct berval pw[] = {
+ { sizeof("secret")-1, "secret" },
+ { sizeof("binary\0secret")-1, "binary\0secret" },
+ { 0, NULL }
+};
+
+int
+main( int argc, char *argv[] )
+{
+ int i, j, rc;
+ struct berval *passwd;
+#ifdef SLAP_AUTHPASSWD
+ struct berval *salt;
+#endif
+ struct berval bad;
+ bad.bv_val = "bad password";
+ bad.bv_len = sizeof("bad password")-1;
+
+ for( i= 0; hash[i]; i++ ) {
+ for( j = 0; pw[j].bv_len; j++ ) {
+#ifdef SLAP_AUTHPASSWD
+ rc = lutil_authpasswd_hash( &pw[j],
+ &passwd, &salt, hash[i] );
+
+ if( rc )
+#else
+ passwd = lutil_passwd_hash( &pw[j], hash[i] );
+
+ if( passwd == NULL )
+#endif
+ {
+ printf("%s generate fail: %s (%d)\n",
+ hash[i], pw[j].bv_val, pw[j].bv_len );
+ continue;
+ }
+
+
+#ifdef SLAP_AUTHPASSWD
+ rc = lutil_authpasswd( &pw[j], passwd, salt, NULL );
+#else
+ rc = lutil_passwd( passwd, &pw[j], NULL );
+#endif
+
+ printf("%s (%d): %s (%d)\t(%d) %s\n",
+ pw[j].bv_val, pw[j].bv_len, passwd->bv_val, passwd->bv_len,
+ rc, rc == 0 ? "OKAY" : "BAD" );
+
+#ifdef SLAP_AUTHPASSWD
+ rc = lutil_authpasswd( passwd, salt, &bad, NULL );
+#else
+ rc = lutil_passwd( passwd, &bad, NULL );
+#endif
+
+ printf("%s (%d): %s (%d)\t(%d) %s\n",
+ bad.bv_val, bad.bv_len, passwd->bv_val, passwd->bv_len,
+ rc, rc != 0 ? "OKAY" : "BAD" );
+ }
+
+ printf("\n");
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/libraries/liblutil/sasl.c b/libraries/liblutil/sasl.c
new file mode 100644
index 0000000..b9830f4
--- /dev/null
+++ b/libraries/liblutil/sasl.c
@@ -0,0 +1,234 @@
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 1998-2018 The OpenLDAP Foundation.
+ * 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 the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+
+#include "portable.h"
+
+#ifdef HAVE_CYRUS_SASL
+
+#include <stdio.h>
+#include <ac/stdlib.h>
+#include <ac/string.h>
+#include <ac/unistd.h>
+
+#ifdef HAVE_SASL_SASL_H
+#include <sasl/sasl.h>
+#else
+#include <sasl.h>
+#endif
+
+#include <ldap.h>
+#include "ldap_pvt.h"
+#include "lutil_ldap.h"
+
+
+typedef struct lutil_sasl_defaults_s {
+ char *mech;
+ char *realm;
+ char *authcid;
+ char *passwd;
+ char *authzid;
+ char **resps;
+ int nresps;
+} lutilSASLdefaults;
+
+
+void
+lutil_sasl_freedefs(
+ void *defaults )
+{
+ lutilSASLdefaults *defs = defaults;
+
+ assert( defs != NULL );
+
+ if (defs->mech) ber_memfree(defs->mech);
+ if (defs->realm) ber_memfree(defs->realm);
+ if (defs->authcid) ber_memfree(defs->authcid);
+ if (defs->passwd) ber_memfree(defs->passwd);
+ if (defs->authzid) ber_memfree(defs->authzid);
+ if (defs->resps) ldap_charray_free(defs->resps);
+
+ ber_memfree(defs);
+}
+
+void *
+lutil_sasl_defaults(
+ LDAP *ld,
+ char *mech,
+ char *realm,
+ char *authcid,
+ char *passwd,
+ char *authzid )
+{
+ lutilSASLdefaults *defaults;
+
+ defaults = ber_memalloc( sizeof( lutilSASLdefaults ) );
+
+ if( defaults == NULL ) return NULL;
+
+ defaults->mech = mech ? ber_strdup(mech) : NULL;
+ defaults->realm = realm ? ber_strdup(realm) : NULL;
+ defaults->authcid = authcid ? ber_strdup(authcid) : NULL;
+ defaults->passwd = passwd ? ber_strdup(passwd) : NULL;
+ defaults->authzid = authzid ? ber_strdup(authzid) : NULL;
+
+ if( defaults->mech == NULL ) {
+ ldap_get_option( ld, LDAP_OPT_X_SASL_MECH, &defaults->mech );
+ }
+ if( defaults->realm == NULL ) {
+ ldap_get_option( ld, LDAP_OPT_X_SASL_REALM, &defaults->realm );
+ }
+ if( defaults->authcid == NULL ) {
+ ldap_get_option( ld, LDAP_OPT_X_SASL_AUTHCID, &defaults->authcid );
+ }
+ if( defaults->authzid == NULL ) {
+ ldap_get_option( ld, LDAP_OPT_X_SASL_AUTHZID, &defaults->authzid );
+ }
+ defaults->resps = NULL;
+ defaults->nresps = 0;
+
+ return defaults;
+}
+
+static int interaction(
+ unsigned flags,
+ sasl_interact_t *interact,
+ lutilSASLdefaults *defaults )
+{
+ const char *dflt = interact->defresult;
+ char input[1024];
+
+ int noecho=0;
+ int challenge=0;
+
+ switch( interact->id ) {
+ case SASL_CB_GETREALM:
+ if( defaults ) dflt = defaults->realm;
+ break;
+ case SASL_CB_AUTHNAME:
+ if( defaults ) dflt = defaults->authcid;
+ break;
+ case SASL_CB_PASS:
+ if( defaults ) dflt = defaults->passwd;
+ noecho = 1;
+ break;
+ case SASL_CB_USER:
+ if( defaults ) dflt = defaults->authzid;
+ break;
+ case SASL_CB_NOECHOPROMPT:
+ noecho = 1;
+ challenge = 1;
+ break;
+ case SASL_CB_ECHOPROMPT:
+ challenge = 1;
+ break;
+ }
+
+ if( dflt && !*dflt ) dflt = NULL;
+
+ if( flags != LDAP_SASL_INTERACTIVE &&
+ ( dflt || interact->id == SASL_CB_USER ) )
+ {
+ goto use_default;
+ }
+
+ if( flags == LDAP_SASL_QUIET ) {
+ /* don't prompt */
+ return LDAP_OTHER;
+ }
+
+ if( challenge ) {
+ if( interact->challenge ) {
+ fprintf( stderr, _("Challenge: %s\n"), interact->challenge );
+ }
+ }
+
+ if( dflt ) {
+ fprintf( stderr, _("Default: %s\n"), dflt );
+ }
+
+ snprintf( input, sizeof input, "%s: ",
+ interact->prompt ? interact->prompt : _("Interact") );
+
+ if( noecho ) {
+ interact->result = (char *) getpassphrase( input );
+ interact->len = interact->result
+ ? strlen( interact->result ) : 0;
+
+ } else {
+ /* prompt user */
+ fputs( input, stderr );
+
+ /* get input */
+ interact->result = fgets( input, sizeof(input), stdin );
+
+ if( interact->result == NULL ) {
+ interact->len = 0;
+ return LDAP_UNAVAILABLE;
+ }
+
+ /* len of input */
+ interact->len = strlen(input);
+
+ if( interact->len > 0 && input[interact->len - 1] == '\n' ) {
+ /* input includes '\n', trim it */
+ interact->len--;
+ input[interact->len] = '\0';
+ }
+ }
+
+
+ if( interact->len > 0 ) {
+ /* duplicate */
+ char *p = (char *)interact->result;
+ ldap_charray_add(&defaults->resps, interact->result);
+ interact->result = defaults->resps[defaults->nresps++];
+
+ /* zap */
+ memset( p, '\0', interact->len );
+
+ } else {
+use_default:
+ /* input must be empty */
+ interact->result = (dflt && *dflt) ? dflt : "";
+ interact->len = strlen( interact->result );
+ }
+
+ return LDAP_SUCCESS;
+}
+
+int lutil_sasl_interact(
+ LDAP *ld,
+ unsigned flags,
+ void *defaults,
+ void *in )
+{
+ sasl_interact_t *interact = in;
+
+ if( ld == NULL ) return LDAP_PARAM_ERROR;
+
+ if( flags == LDAP_SASL_INTERACTIVE ) {
+ fputs( _("SASL Interaction\n"), stderr );
+ }
+
+ while( interact->id != SASL_CB_LIST_END ) {
+ int rc = interaction( flags, interact, defaults );
+
+ if( rc ) return rc;
+ interact++;
+ }
+
+ return LDAP_SUCCESS;
+}
+#endif
diff --git a/libraries/liblutil/setproctitle.c b/libraries/liblutil/setproctitle.c
new file mode 100644
index 0000000..fe7f729
--- /dev/null
+++ b/libraries/liblutil/setproctitle.c
@@ -0,0 +1,78 @@
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 1998-2018 The OpenLDAP Foundation.
+ * 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 the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* Portions Copyright (c) 1990,1991 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+
+#include "portable.h"
+
+#ifndef HAVE_SETPROCTITLE
+
+#include <stdio.h>
+
+#include <ac/stdlib.h>
+
+#include <ac/setproctitle.h>
+#include <ac/string.h>
+#include <ac/stdarg.h>
+
+char **Argv; /* pointer to original (main's) argv */
+int Argc; /* original argc */
+
+/*
+ * takes a printf-style format string (fmt) and up to three parameters (a,b,c)
+ * this clobbers the original argv...
+ */
+
+/* VARARGS */
+void setproctitle( const char *fmt, ... )
+{
+ static char *endargv = (char *)0;
+ char *s;
+ int i;
+ char buf[ 1024 ];
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ buf[sizeof(buf) - 1] = '\0';
+ vsnprintf( buf, sizeof(buf)-1, fmt, ap );
+
+ va_end(ap);
+
+ if ( endargv == (char *)0 ) {
+ /* set pointer to end of original argv */
+ endargv = Argv[ Argc-1 ] + strlen( Argv[ Argc-1 ] );
+ }
+ /* make ps print "([prog name])" */
+ s = Argv[0];
+ *s++ = '-';
+ i = strlen( buf );
+ if ( i > endargv - s - 2 ) {
+ i = endargv - s - 2;
+ buf[ i ] = '\0';
+ }
+ strcpy( s, buf );
+ s += i;
+ while ( s < endargv ) *s++ = ' ';
+}
+#endif /* NOSETPROCTITLE */
diff --git a/libraries/liblutil/sha1.c b/libraries/liblutil/sha1.c
new file mode 100644
index 0000000..5fed7f2
--- /dev/null
+++ b/libraries/liblutil/sha1.c
@@ -0,0 +1,288 @@
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 1998-2018 The OpenLDAP Foundation.
+ * 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 the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* This work was derived from code developed by Steve Reid and
+ * adapted for use in OpenLDAP by Kurt D. Zeilenga.
+ */
+
+
+/* Acquired from:
+ * $OpenBSD: sha1.c,v 1.9 1997/07/23 21:12:32 kstailey Exp $ */
+/*
+ * SHA-1 in C
+ * By Steve Reid <steve@edmweb.com>
+ * 100% Public Domain
+ *
+ * Test Vectors (from FIPS PUB 180-1)
+ * "abc"
+ * A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
+ * "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+ * 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
+ * A million repetitions of "a"
+ * 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
+ */
+/*
+ * This code assumes uint32 is 32 bits and char is 8 bits
+ */
+
+#include "portable.h"
+#include <ac/param.h>
+#include <ac/string.h>
+#include <ac/socket.h>
+#include <ac/bytes.h>
+
+#include "lutil_sha1.h"
+
+#ifdef LUTIL_SHA1_BYTES
+
+/* undefining this will cause pointer alignment errors */
+#define SHA1HANDSOFF /* Copies data before messing with it. */
+#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+/*
+ * blk0() and blk() perform the initial expand.
+ * I got the idea of expanding during the round function from SSLeay
+ */
+#if BYTE_ORDER == LITTLE_ENDIAN
+# define blk0(i) (block[i] = (rol(block[i],24)&0xFF00FF00) \
+ |(rol(block[i],8)&0x00FF00FF))
+#else
+# define blk0(i) block[i]
+#endif
+#define blk(i) (block[i&15] = rol(block[(i+13)&15]^block[(i+8)&15] \
+ ^block[(i+2)&15]^block[i&15],1))
+
+/*
+ * (R0+R1), R2, R3, R4 are the different operations (rounds) used in SHA1
+ */
+#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
+#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
+#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
+
+
+/*
+ * Hash a single 512-bit block. This is the core of the algorithm.
+ */
+void
+lutil_SHA1Transform( uint32 *state, const unsigned char *buffer )
+{
+ uint32 a, b, c, d, e;
+
+#ifdef SHA1HANDSOFF
+ uint32 block[16];
+ (void)AC_MEMCPY(block, buffer, 64);
+#else
+ uint32 *block = (u_int32 *) buffer;
+#endif
+
+ /* Copy context->state[] to working vars */
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+ e = state[4];
+
+ /* 4 rounds of 20 operations each. Loop unrolled. */
+ R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
+ R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
+ R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
+ R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
+ R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
+ R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
+ R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
+ R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
+ R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
+ R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
+ R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
+ R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
+ R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
+ R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
+ R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
+ R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
+ R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
+ R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
+ R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
+ R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
+
+ /* Add the working vars back into context.state[] */
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+ state[4] += e;
+
+ /* Wipe variables */
+ a = b = c = d = e = 0;
+}
+
+
+/*
+ * lutil_SHA1Init - Initialize new context
+ */
+void
+lutil_SHA1Init( lutil_SHA1_CTX *context )
+{
+
+ /* SHA1 initialization constants */
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xEFCDAB89;
+ context->state[2] = 0x98BADCFE;
+ context->state[3] = 0x10325476;
+ context->state[4] = 0xC3D2E1F0;
+ context->count[0] = context->count[1] = 0;
+}
+
+
+/*
+ * Run your data through this.
+ */
+void
+lutil_SHA1Update(
+ lutil_SHA1_CTX *context,
+ const unsigned char *data,
+ uint32 len
+)
+{
+ u_int i, j;
+
+ j = context->count[0];
+ if ((context->count[0] += len << 3) < j)
+ context->count[1] += (len>>29)+1;
+ j = (j >> 3) & 63;
+ if ((j + len) > 63) {
+ (void)AC_MEMCPY(&context->buffer[j], data, (i = 64-j));
+ lutil_SHA1Transform(context->state, context->buffer);
+ for ( ; i + 63 < len; i += 64)
+ lutil_SHA1Transform(context->state, &data[i]);
+ j = 0;
+ } else {
+ i = 0;
+ }
+ (void)AC_MEMCPY(&context->buffer[j], &data[i], len - i);
+}
+
+
+/*
+ * Add padding and return the message digest.
+ */
+void
+lutil_SHA1Final( unsigned char *digest, lutil_SHA1_CTX *context )
+{
+ u_int i;
+ unsigned char finalcount[8];
+
+ for (i = 0; i < 8; i++) {
+ finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
+ >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
+ }
+ lutil_SHA1Update(context, (unsigned char *)"\200", 1);
+ while ((context->count[0] & 504) != 448)
+ lutil_SHA1Update(context, (unsigned char *)"\0", 1);
+ lutil_SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */
+
+ if (digest) {
+ for (i = 0; i < 20; i++)
+ digest[i] = (unsigned char)
+ ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
+ }
+}
+
+
+/* sha1hl.c
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@login.dkuug.dk> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char rcsid[] = "$OpenBSD: sha1hl.c,v 1.1 1997/07/12 20:06:03 millert Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <stdio.h>
+#include <ac/stdlib.h>
+
+#include <ac/errno.h>
+#include <ac/unistd.h>
+
+#ifdef HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+
+#ifdef HAVE_IO_H
+#include <io.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+
+/* ARGSUSED */
+char *
+lutil_SHA1End( lutil_SHA1_CTX *ctx, char *buf )
+{
+ int i;
+ char *p = buf;
+ unsigned char digest[20];
+ static const char hex[]="0123456789abcdef";
+
+ if (p == NULL && (p = malloc(41)) == NULL)
+ return 0;
+
+ lutil_SHA1Final(digest,ctx);
+ for (i = 0; i < 20; i++) {
+ p[i + i] = hex[digest[i] >> 4];
+ p[i + i + 1] = hex[digest[i] & 0x0f];
+ }
+ p[i + i] = '\0';
+ return(p);
+}
+
+char *
+lutil_SHA1File( char *filename, char *buf )
+{
+ unsigned char buffer[BUFSIZ];
+ lutil_SHA1_CTX ctx;
+ int fd, num, oerrno;
+
+ lutil_SHA1Init(&ctx);
+
+ if ((fd = open(filename,O_RDONLY)) < 0)
+ return(0);
+
+ while ((num = read(fd, buffer, sizeof(buffer))) > 0)
+ lutil_SHA1Update(&ctx, buffer, num);
+
+ oerrno = errno;
+ close(fd);
+ errno = oerrno;
+ return(num < 0 ? 0 : lutil_SHA1End(&ctx, buf));
+}
+
+char *
+lutil_SHA1Data( const unsigned char *data, size_t len, char *buf )
+{
+ lutil_SHA1_CTX ctx;
+
+ lutil_SHA1Init(&ctx);
+ lutil_SHA1Update(&ctx, data, len);
+ return(lutil_SHA1End(&ctx, buf));
+}
+
+#endif
diff --git a/libraries/liblutil/signal.c b/libraries/liblutil/signal.c
new file mode 100644
index 0000000..6a44e30
--- /dev/null
+++ b/libraries/liblutil/signal.c
@@ -0,0 +1,41 @@
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 1998-2018 The OpenLDAP Foundation.
+ * 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 the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+
+#include "portable.h"
+
+#ifdef HAVE_SIGACTION
+#include <ac/string.h>
+#include <ac/signal.h>
+
+lutil_sig_t
+lutil_sigaction(int sig, lutil_sig_t func)
+{
+ struct sigaction action, oaction;
+
+ memset( &action, '\0', sizeof(action) );
+
+ action.sa_handler = func;
+ sigemptyset( &action.sa_mask );
+#ifdef SA_RESTART
+ action.sa_flags |= SA_RESTART;
+#endif
+
+ if( sigaction( sig, &action, &oaction ) != 0 ) {
+ return NULL;
+ }
+
+ return oaction.sa_handler;
+}
+#endif
diff --git a/libraries/liblutil/slapdmsg.bin b/libraries/liblutil/slapdmsg.bin
new file mode 100644
index 0000000..d8ca806
--- /dev/null
+++ b/libraries/liblutil/slapdmsg.bin
Binary files differ
diff --git a/libraries/liblutil/slapdmsg.h b/libraries/liblutil/slapdmsg.h
new file mode 100644
index 0000000..21a84fb
--- /dev/null
+++ b/libraries/liblutil/slapdmsg.h
@@ -0,0 +1,65 @@
+//
+// This file contains message strings for the OpenLDAP slapd service.
+//
+// This file should be compiled as follows
+// mc -v slapdmsg.mc -r $(IntDir)
+// rc /v /r $(IntDir)\slapdmsg.rc
+// The mc (message compiler) command generates the .rc and .h files from this file. The
+// rc (resource compiler) takes the .rc file and produces a .res file that can be linked
+// with the final executable application. The application is then registered as a message
+// source with by creating the appropriate entries in the system registry.
+//
+//
+// Values are 32 bit values layed out as follows:
+//
+// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
+// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+// +---+-+-+-----------------------+-------------------------------+
+// |Sev|C|R| Facility | Code |
+// +---+-+-+-----------------------+-------------------------------+
+//
+// where
+//
+// Sev - is the severity code
+//
+// 00 - Success
+// 01 - Informational
+// 10 - Warning
+// 11 - Error
+//
+// C - is the Customer code flag
+//
+// R - is a reserved bit
+//
+// Facility - is the facility code
+//
+// Code - is the facility's status code
+//
+//
+// Define the facility codes
+//
+
+
+//
+// Define the severity codes
+//
+
+
+//
+// MessageId: MSG_SVC_STARTED
+//
+// MessageText:
+//
+// OpenLDAP service started. debuglevel=%1, conffile=%2, urls=%3
+//
+#define MSG_SVC_STARTED 0x40000500L
+
+//
+// MessageId: MSG_SVC_STOPPED
+//
+// MessageText:
+//
+// OpenLDAP service stopped.
+//
+#define MSG_SVC_STOPPED 0x40000501L
+
diff --git a/libraries/liblutil/slapdmsg.mc b/libraries/liblutil/slapdmsg.mc
new file mode 100644
index 0000000..53401f0
--- /dev/null
+++ b/libraries/liblutil/slapdmsg.mc
@@ -0,0 +1,28 @@
+;//
+;// This file contains message strings for the OpenLDAP slapd service.
+;//
+;// This file should be compiled as follows
+;// mc -v slapdmsg.mc -r $(IntDir)
+;// rc /v /r $(IntDir)\slapdmsg.rc
+;// The mc (message compiler) command generates the .rc and .h files from this file. The
+;// rc (resource compiler) takes the .rc file and produces a .res file that can be linked
+;// with the final executable application. The application is then registered as a message
+;// source with by creating the appropriate entries in the system registry.
+;//
+
+MessageID=0x500
+Severity=Informational
+SymbolicName=MSG_SVC_STARTED
+Facility=Application
+Language=English
+OpenLDAP service started. debuglevel=%1, conffile=%2, urls=%3
+.
+
+
+MessageID=0x501
+Severity=Informational
+SymbolicName=MSG_SVC_STOPPED
+Facility=Application
+Language=English
+OpenLDAP service stopped.
+.
diff --git a/libraries/liblutil/slapdmsg.rc b/libraries/liblutil/slapdmsg.rc
new file mode 100644
index 0000000..f967de2
--- /dev/null
+++ b/libraries/liblutil/slapdmsg.rc
@@ -0,0 +1,2 @@
+LANGUAGE 0x9,0x1
+1 11 slapdmsg.bin
diff --git a/libraries/liblutil/sockpair.c b/libraries/liblutil/sockpair.c
new file mode 100644
index 0000000..184615f
--- /dev/null
+++ b/libraries/liblutil/sockpair.c
@@ -0,0 +1,78 @@
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 1998-2018 The OpenLDAP Foundation.
+ * 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 the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+
+#include "portable.h"
+#include <ac/socket.h>
+#include <ac/unistd.h>
+
+#include <lutil.h>
+
+/* Return a pair of socket descriptors that are connected to each other.
+ * The returned descriptors are suitable for use with select(). The two
+ * descriptors may or may not be identical; the function may return
+ * the same descriptor number in both slots. It is guaranteed that
+ * data written on sds[1] will be readable on sds[0]. The returned
+ * descriptors may be datagram oriented, so data should be written
+ * in reasonably small pieces and read all at once. On Unix systems
+ * this function is best implemented using a single pipe() call.
+ */
+
+int lutil_pair( ber_socket_t sds[2] )
+{
+#ifdef USE_PIPE
+ return pipe( sds );
+#else
+ struct sockaddr_in si;
+ int rc;
+ ber_socklen_t len = sizeof(si);
+ ber_socket_t sd;
+
+ sd = socket( AF_INET, SOCK_DGRAM, 0 );
+ if ( sd == AC_SOCKET_INVALID ) {
+ return sd;
+ }
+
+ (void) memset( (void*) &si, '\0', len );
+ si.sin_family = AF_INET;
+ si.sin_port = 0;
+ si.sin_addr.s_addr = htonl( INADDR_LOOPBACK );
+
+ rc = bind( sd, (struct sockaddr *)&si, len );
+ if ( rc == AC_SOCKET_ERROR ) {
+ tcp_close(sd);
+ return rc;
+ }
+
+ rc = getsockname( sd, (struct sockaddr *)&si, &len );
+ if ( rc == AC_SOCKET_ERROR ) {
+ tcp_close(sd);
+ return rc;
+ }
+
+ rc = connect( sd, (struct sockaddr *)&si, len );
+ if ( rc == AC_SOCKET_ERROR ) {
+ tcp_close(sd);
+ return rc;
+ }
+
+ sds[0] = sd;
+#if !HAVE_WINSOCK
+ sds[1] = dup( sds[0] );
+#else
+ sds[1] = sds[0];
+#endif
+ return 0;
+#endif
+}
diff --git a/libraries/liblutil/tavl.c b/libraries/liblutil/tavl.c
new file mode 100644
index 0000000..320ffaa
--- /dev/null
+++ b/libraries/liblutil/tavl.c
@@ -0,0 +1,523 @@
+/* avl.c - routines to implement an avl tree */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2005-2018 The OpenLDAP Foundation.
+ * Portions Copyright (c) 2005 by Howard Chu, Symas Corp.
+ * 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 the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was initially developed by Howard Chu for inclusion
+ * in OpenLDAP software.
+ */
+
+#include "portable.h"
+
+#include <limits.h>
+#include <stdio.h>
+#include <ac/stdlib.h>
+
+#ifdef CSRIMALLOC
+#define ber_memalloc malloc
+#define ber_memrealloc realloc
+#define ber_memfree free
+#else
+#include "lber.h"
+#endif
+
+#define AVL_INTERNAL
+#include "avl.h"
+
+/* Maximum tree depth this host's address space could support */
+#define MAX_TREE_DEPTH (sizeof(void *) * CHAR_BIT)
+
+static const int avl_bfs[] = {LH, RH};
+
+/*
+ * Threaded AVL trees - for fast in-order traversal of nodes.
+ */
+/*
+ * tavl_insert -- insert a node containing data data into the avl tree
+ * with root root. fcmp is a function to call to compare the data portion
+ * of two nodes. it should take two arguments and return <, >, or == 0,
+ * depending on whether its first argument is <, >, or == its second
+ * argument (like strcmp, e.g.). fdup is a function to call when a duplicate
+ * node is inserted. it should return 0, or -1 and its return value
+ * will be the return value from avl_insert in the case of a duplicate node.
+ * the function will be called with the original node's data as its first
+ * argument and with the incoming duplicate node's data as its second
+ * argument. this could be used, for example, to keep a count with each
+ * node.
+ *
+ * NOTE: this routine may malloc memory
+ */
+int
+tavl_insert( Avlnode ** root, void *data, AVL_CMP fcmp, AVL_DUP fdup )
+{
+ Avlnode *t, *p, *s, *q, *r;
+ int a, cmp, ncmp;
+
+ if ( *root == NULL ) {
+ if (( r = (Avlnode *) ber_memalloc( sizeof( Avlnode ))) == NULL ) {
+ return( -1 );
+ }
+ r->avl_link[0] = r->avl_link[1] = NULL;
+ r->avl_data = data;
+ r->avl_bf = EH;
+ r->avl_bits[0] = r->avl_bits[1] = AVL_THREAD;
+ *root = r;
+
+ return( 0 );
+ }
+
+ t = NULL;
+ s = p = *root;
+
+ /* find insertion point */
+ while (1) {
+ cmp = fcmp( data, p->avl_data );
+ if ( cmp == 0 )
+ return (*fdup)( p->avl_data, data );
+
+ cmp = (cmp > 0);
+ q = avl_child( p, cmp );
+ if (q == NULL) {
+ /* insert */
+ if (( q = (Avlnode *) ber_memalloc( sizeof( Avlnode ))) == NULL ) {
+ return( -1 );
+ }
+ q->avl_link[cmp] = p->avl_link[cmp];
+ q->avl_link[!cmp] = p;
+ q->avl_data = data;
+ q->avl_bf = EH;
+ q->avl_bits[0] = q->avl_bits[1] = AVL_THREAD;
+
+ p->avl_link[cmp] = q;
+ p->avl_bits[cmp] = AVL_CHILD;
+ break;
+ } else if ( q->avl_bf ) {
+ t = p;
+ s = q;
+ }
+ p = q;
+ }
+
+ /* adjust balance factors */
+ cmp = fcmp( data, s->avl_data ) > 0;
+ r = p = s->avl_link[cmp];
+ a = avl_bfs[cmp];
+
+ while ( p != q ) {
+ cmp = fcmp( data, p->avl_data ) > 0;
+ p->avl_bf = avl_bfs[cmp];
+ p = p->avl_link[cmp];
+ }
+
+ /* checks and balances */
+
+ if ( s->avl_bf == EH ) {
+ s->avl_bf = a;
+ return 0;
+ } else if ( s->avl_bf == -a ) {
+ s->avl_bf = EH;
+ return 0;
+ } else if ( s->avl_bf == a ) {
+ cmp = (a > 0);
+ ncmp = !cmp;
+ if ( r->avl_bf == a ) {
+ /* single rotation */
+ p = r;
+ if ( r->avl_bits[ncmp] == AVL_THREAD ) {
+ r->avl_bits[ncmp] = AVL_CHILD;
+ s->avl_bits[cmp] = AVL_THREAD;
+ } else {
+ s->avl_link[cmp] = r->avl_link[ncmp];
+ r->avl_link[ncmp] = s;
+ }
+ s->avl_bf = 0;
+ r->avl_bf = 0;
+ } else if ( r->avl_bf == -a ) {
+ /* double rotation */
+ p = r->avl_link[ncmp];
+ if ( p->avl_bits[cmp] == AVL_THREAD ) {
+ p->avl_bits[cmp] = AVL_CHILD;
+ r->avl_bits[ncmp] = AVL_THREAD;
+ } else {
+ r->avl_link[ncmp] = p->avl_link[cmp];
+ p->avl_link[cmp] = r;
+ }
+ if ( p->avl_bits[ncmp] == AVL_THREAD ) {
+ p->avl_bits[ncmp] = AVL_CHILD;
+ s->avl_link[cmp] = p;
+ s->avl_bits[cmp] = AVL_THREAD;
+ } else {
+ s->avl_link[cmp] = p->avl_link[ncmp];
+ p->avl_link[ncmp] = s;
+ }
+ if ( p->avl_bf == a ) {
+ s->avl_bf = -a;
+ r->avl_bf = 0;
+ } else if ( p->avl_bf == -a ) {
+ s->avl_bf = 0;
+ r->avl_bf = a;
+ } else {
+ s->avl_bf = 0;
+ r->avl_bf = 0;
+ }
+ p->avl_bf = 0;
+ }
+ /* Update parent */
+ if ( t == NULL )
+ *root = p;
+ else if ( s == t->avl_right )
+ t->avl_right = p;
+ else
+ t->avl_left = p;
+ }
+
+ return 0;
+}
+
+void*
+tavl_delete( Avlnode **root, void* data, AVL_CMP fcmp )
+{
+ Avlnode *p, *q, *r, *top;
+ int side, side_bf, shorter, nside = -1;
+
+ /* parent stack */
+ Avlnode *pptr[MAX_TREE_DEPTH];
+ unsigned char pdir[MAX_TREE_DEPTH];
+ int depth = 0;
+
+ if ( *root == NULL )
+ return NULL;
+
+ p = *root;
+
+ while (1) {
+ side = fcmp( data, p->avl_data );
+ if ( !side )
+ break;
+ side = ( side > 0 );
+ pdir[depth] = side;
+ pptr[depth++] = p;
+
+ if ( p->avl_bits[side] == AVL_THREAD )
+ return NULL;
+ p = p->avl_link[side];
+ }
+ data = p->avl_data;
+
+ /* If this node has two children, swap so we are deleting a node with
+ * at most one child.
+ */
+ if ( p->avl_bits[0] == AVL_CHILD && p->avl_bits[1] == AVL_CHILD &&
+ p->avl_link[0] && p->avl_link[1] ) {
+
+ /* find the immediate predecessor <q> */
+ q = p->avl_link[0];
+ side = depth;
+ pdir[depth++] = 0;
+ while (q->avl_bits[1] == AVL_CHILD && q->avl_link[1]) {
+ pdir[depth] = 1;
+ pptr[depth++] = q;
+ q = q->avl_link[1];
+ }
+ /* swap links */
+ r = p->avl_link[0];
+ p->avl_link[0] = q->avl_link[0];
+ q->avl_link[0] = r;
+
+ q->avl_link[1] = p->avl_link[1];
+ p->avl_link[1] = q;
+
+ p->avl_bits[0] = q->avl_bits[0];
+ p->avl_bits[1] = q->avl_bits[1];
+ q->avl_bits[0] = q->avl_bits[1] = AVL_CHILD;
+
+ q->avl_bf = p->avl_bf;
+
+ /* fix stack positions: old parent of p points to q */
+ pptr[side] = q;
+ if ( side ) {
+ r = pptr[side-1];
+ r->avl_link[pdir[side-1]] = q;
+ } else {
+ *root = q;
+ }
+ /* new parent of p points to p */
+ if ( depth-side > 1 ) {
+ r = pptr[depth-1];
+ r->avl_link[1] = p;
+ } else {
+ q->avl_link[0] = p;
+ }
+
+ /* fix right subtree: successor of p points to q */
+ r = q->avl_link[1];
+ while ( r->avl_bits[0] == AVL_CHILD && r->avl_link[0] )
+ r = r->avl_link[0];
+ r->avl_link[0] = q;
+ }
+
+ /* now <p> has at most one child, get it */
+ if ( p->avl_link[0] && p->avl_bits[0] == AVL_CHILD ) {
+ q = p->avl_link[0];
+ /* Preserve thread continuity */
+ r = p->avl_link[1];
+ nside = 1;
+ } else if ( p->avl_link[1] && p->avl_bits[1] == AVL_CHILD ) {
+ q = p->avl_link[1];
+ r = p->avl_link[0];
+ nside = 0;
+ } else {
+ q = NULL;
+ if ( depth > 0 )
+ r = p->avl_link[pdir[depth-1]];
+ else
+ r = NULL;
+ }
+
+ ber_memfree( p );
+
+ /* Update child thread */
+ if ( q ) {
+ for ( ; q->avl_bits[nside] == AVL_CHILD && q->avl_link[nside];
+ q = q->avl_link[nside] ) ;
+ q->avl_link[nside] = r;
+ }
+
+ if ( !depth ) {
+ *root = q;
+ return data;
+ }
+
+ /* set the child into p's parent */
+ depth--;
+ p = pptr[depth];
+ side = pdir[depth];
+ p->avl_link[side] = q;
+
+ if ( !q ) {
+ p->avl_bits[side] = AVL_THREAD;
+ p->avl_link[side] = r;
+ }
+
+ top = NULL;
+ shorter = 1;
+
+ while ( shorter ) {
+ p = pptr[depth];
+ side = pdir[depth];
+ nside = !side;
+ side_bf = avl_bfs[side];
+
+ /* case 1: height unchanged */
+ if ( p->avl_bf == EH ) {
+ /* Tree is now heavier on opposite side */
+ p->avl_bf = avl_bfs[nside];
+ shorter = 0;
+
+ } else if ( p->avl_bf == side_bf ) {
+ /* case 2: taller subtree shortened, height reduced */
+ p->avl_bf = EH;
+ } else {
+ /* case 3: shorter subtree shortened */
+ if ( depth )
+ top = pptr[depth-1]; /* p->parent; */
+ else
+ top = NULL;
+ /* set <q> to the taller of the two subtrees of <p> */
+ q = p->avl_link[nside];
+ if ( q->avl_bf == EH ) {
+ /* case 3a: height unchanged, single rotate */
+ if ( q->avl_bits[side] == AVL_THREAD ) {
+ q->avl_bits[side] = AVL_CHILD;
+ p->avl_bits[nside] = AVL_THREAD;
+ } else {
+ p->avl_link[nside] = q->avl_link[side];
+ q->avl_link[side] = p;
+ }
+ shorter = 0;
+ q->avl_bf = side_bf;
+ p->avl_bf = (- side_bf);
+
+ } else if ( q->avl_bf == p->avl_bf ) {
+ /* case 3b: height reduced, single rotate */
+ if ( q->avl_bits[side] == AVL_THREAD ) {
+ q->avl_bits[side] = AVL_CHILD;
+ p->avl_bits[nside] = AVL_THREAD;
+ } else {
+ p->avl_link[nside] = q->avl_link[side];
+ q->avl_link[side] = p;
+ }
+ shorter = 1;
+ q->avl_bf = EH;
+ p->avl_bf = EH;
+
+ } else {
+ /* case 3c: height reduced, balance factors opposite */
+ r = q->avl_link[side];
+ if ( r->avl_bits[nside] == AVL_THREAD ) {
+ r->avl_bits[nside] = AVL_CHILD;
+ q->avl_bits[side] = AVL_THREAD;
+ } else {
+ q->avl_link[side] = r->avl_link[nside];
+ r->avl_link[nside] = q;
+ }
+
+ if ( r->avl_bits[side] == AVL_THREAD ) {
+ r->avl_bits[side] = AVL_CHILD;
+ p->avl_bits[nside] = AVL_THREAD;
+ p->avl_link[nside] = r;
+ } else {
+ p->avl_link[nside] = r->avl_link[side];
+ r->avl_link[side] = p;
+ }
+
+ if ( r->avl_bf == side_bf ) {
+ q->avl_bf = (- side_bf);
+ p->avl_bf = EH;
+ } else if ( r->avl_bf == (- side_bf)) {
+ q->avl_bf = EH;
+ p->avl_bf = side_bf;
+ } else {
+ q->avl_bf = EH;
+ p->avl_bf = EH;
+ }
+ r->avl_bf = EH;
+ q = r;
+ }
+ /* a rotation has caused <q> (or <r> in case 3c) to become
+ * the root. let <p>'s former parent know this.
+ */
+ if ( top == NULL ) {
+ *root = q;
+ } else if (top->avl_link[0] == p) {
+ top->avl_link[0] = q;
+ } else {
+ top->avl_link[1] = q;
+ }
+ /* end case 3 */
+ p = q;
+ }
+ if ( !depth )
+ break;
+ depth--;
+ } /* end while(shorter) */
+
+ return data;
+}
+
+/*
+ * tavl_free -- traverse avltree root, freeing the memory it is using.
+ * the dfree() is called to free the data portion of each node. The
+ * number of items actually freed is returned.
+ */
+
+int
+tavl_free( Avlnode *root, AVL_FREE dfree )
+{
+ int nleft, nright;
+
+ if ( root == 0 )
+ return( 0 );
+
+ nleft = tavl_free( avl_lchild( root ), dfree );
+
+ nright = tavl_free( avl_rchild( root ), dfree );
+
+ if ( dfree )
+ (*dfree)( root->avl_data );
+ ber_memfree( root );
+
+ return( nleft + nright + 1 );
+}
+
+/*
+ * tavl_find -- search avltree root for a node with data data. the function
+ * cmp is used to compare things. it is called with data as its first arg
+ * and the current node data as its second. it should return 0 if they match,
+ * < 0 if arg1 is less than arg2 and > 0 if arg1 is greater than arg2.
+ */
+
+/*
+ * tavl_find2 - returns Avlnode instead of data pointer.
+ * tavl_find3 - as above, but returns Avlnode even if no match is found.
+ * also set *ret = last comparison result, or -1 if root == NULL.
+ */
+Avlnode *
+tavl_find3( Avlnode *root, const void *data, AVL_CMP fcmp, int *ret )
+{
+ int cmp = -1, dir;
+ Avlnode *prev = root;
+
+ while ( root != 0 && (cmp = (*fcmp)( data, root->avl_data )) != 0 ) {
+ prev = root;
+ dir = cmp > 0;
+ root = avl_child( root, dir );
+ }
+ *ret = cmp;
+ return root ? root : prev;
+}
+
+Avlnode *
+tavl_find2( Avlnode *root, const void *data, AVL_CMP fcmp )
+{
+ int cmp;
+
+ while ( root != 0 && (cmp = (*fcmp)( data, root->avl_data )) != 0 ) {
+ cmp = cmp > 0;
+ root = avl_child( root, cmp );
+ }
+ return root;
+}
+
+void*
+tavl_find( Avlnode *root, const void* data, AVL_CMP fcmp )
+{
+ int cmp;
+
+ while ( root != 0 && (cmp = (*fcmp)( data, root->avl_data )) != 0 ) {
+ cmp = cmp > 0;
+ root = avl_child( root, cmp );
+ }
+
+ return( root ? root->avl_data : 0 );
+}
+
+/* Return the leftmost or rightmost node in the tree */
+Avlnode *
+tavl_end( Avlnode *root, int dir )
+{
+ if ( root ) {
+ while ( root->avl_bits[dir] == AVL_CHILD )
+ root = root->avl_link[dir];
+ }
+ return root;
+}
+
+/* Return the next node in the given direction */
+Avlnode *
+tavl_next( Avlnode *root, int dir )
+{
+ if ( root ) {
+ int c = root->avl_bits[dir];
+
+ root = root->avl_link[dir];
+ if ( c == AVL_CHILD ) {
+ dir ^= 1;
+ while ( root->avl_bits[dir] == AVL_CHILD )
+ root = root->avl_link[dir];
+ }
+ }
+ return root;
+}
diff --git a/libraries/liblutil/testavl.c b/libraries/liblutil/testavl.c
new file mode 100644
index 0000000..e100f68
--- /dev/null
+++ b/libraries/liblutil/testavl.c
@@ -0,0 +1,150 @@
+/* testavl.c - Test Tim Howes AVL code */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 1998-2018 The OpenLDAP Foundation.
+ * 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 the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* Portions Copyright (c) 1993 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was originally developed by the University of Michigan
+ * (as part of U-MICH LDAP).
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/stdlib.h>
+#include <ac/string.h>
+
+#define AVL_INTERNAL
+#define AVL_NONREENTRANT
+#include "avl.h"
+
+static void ravl_print LDAP_P(( Avlnode *root, int depth ));
+static void myprint LDAP_P(( Avlnode *root ));
+static int avl_strcmp LDAP_P(( const void *s, const void *t ));
+
+int
+main( int argc, char **argv )
+{
+ Avlnode *tree = NULL;
+ char command[ 10 ];
+ char name[ 80 ];
+ char *p;
+
+ printf( "> " );
+ while ( fgets( command, sizeof( command ), stdin ) != NULL ) {
+ switch( *command ) {
+ case 'n': /* new tree */
+ ( void ) avl_free( tree, free );
+ tree = NULL;
+ break;
+ case 'p': /* print */
+ ( void ) myprint( tree );
+ break;
+ case 't': /* traverse with first, next */
+#ifdef AVL_NONREENTRANT
+ printf( "***\n" );
+ for ( p = (char * ) avl_getfirst( tree );
+ p != NULL;
+ p = (char *) avl_getnext())
+ printf( "%s\n", p );
+ printf( "***\n" );
+#else
+ printf( "*** reentrant interface not implemented ***" );
+#endif
+ break;
+ case 'f': /* find */
+ printf( "data? " );
+ if ( fgets( name, sizeof( name ), stdin ) == NULL )
+ exit( EXIT_SUCCESS );
+ name[ strlen( name ) - 1 ] = '\0';
+ if ( (p = (char *) avl_find( tree, name, avl_strcmp ))
+ == NULL )
+ printf( "Not found.\n\n" );
+ else
+ printf( "%s\n\n", p );
+ break;
+ case 'i': /* insert */
+ printf( "data? " );
+ if ( fgets( name, sizeof( name ), stdin ) == NULL )
+ exit( EXIT_SUCCESS );
+ name[ strlen( name ) - 1 ] = '\0';
+ if ( avl_insert( &tree, strdup( name ), avl_strcmp,
+ avl_dup_error ) != 0 )
+ printf( "\nNot inserted!\n" );
+ break;
+ case 'd': /* delete */
+ printf( "data? " );
+ if ( fgets( name, sizeof( name ), stdin ) == NULL )
+ exit( EXIT_SUCCESS );
+ name[ strlen( name ) - 1 ] = '\0';
+ if ( avl_delete( &tree, name, avl_strcmp ) == NULL )
+ printf( "\nNot found!\n" );
+ break;
+ case 'q': /* quit */
+ exit( EXIT_SUCCESS );
+ break;
+ case '\n':
+ break;
+ default:
+ printf("Commands: insert, delete, print, new, quit\n");
+ }
+
+ printf( "> " );
+ }
+
+ return( 0 );
+}
+
+static void ravl_print( Avlnode *root, int depth )
+{
+ int i;
+
+ if ( root == 0 )
+ return;
+
+ ravl_print( root->avl_right, depth+1 );
+
+ for ( i = 0; i < depth; i++ )
+ printf( " " );
+ printf( "%s %d\n", (char *) root->avl_data, root->avl_bf );
+
+ ravl_print( root->avl_left, depth+1 );
+}
+
+static void myprint( Avlnode *root )
+{
+ printf( "********\n" );
+
+ if ( root == 0 )
+ printf( "\tNULL\n" );
+ else
+ ravl_print( root, 0 );
+
+ printf( "********\n" );
+}
+
+static int avl_strcmp( const void *s, const void *t )
+{
+ return strcmp( s, t );
+}
diff --git a/libraries/liblutil/testtavl.c b/libraries/liblutil/testtavl.c
new file mode 100644
index 0000000..8374f3e
--- /dev/null
+++ b/libraries/liblutil/testtavl.c
@@ -0,0 +1,158 @@
+/* testavl.c - Test Tim Howes AVL code */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 1998-2018 The OpenLDAP Foundation.
+ * 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 the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* Portions Copyright (c) 1993 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was originally developed by the University of Michigan
+ * (as part of U-MICH LDAP). Additional contributors include
+ * Howard Chu
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/stdlib.h>
+#include <ac/string.h>
+
+#define AVL_INTERNAL
+#include "avl.h"
+
+static void ravl_print LDAP_P(( Avlnode *root, int depth, int thread ));
+static void myprint LDAP_P(( Avlnode *root ));
+static int avl_strcmp LDAP_P(( const void *s, const void *t ));
+
+int
+main( int argc, char **argv )
+{
+ Avlnode *tree = NULL, *n;
+ char command[ 10 ];
+ char name[ 80 ];
+ char *p;
+
+ printf( "> " );
+ while ( fgets( command, sizeof( command ), stdin ) != NULL ) {
+ switch( *command ) {
+ case 'n': /* new tree */
+ ( void ) tavl_free( tree, free );
+ tree = NULL;
+ break;
+ case 'p': /* print */
+ ( void ) myprint( tree );
+ break;
+ case 't': /* traverse with first, next */
+ printf( "***\n" );
+ for ( n = tavl_end( tree, TAVL_DIR_LEFT );
+ n != NULL;
+ n = tavl_next( n, TAVL_DIR_RIGHT ))
+ printf( "%s\n", n->avl_data );
+ printf( "***\n" );
+ break;
+ case 'f': /* find */
+ printf( "data? " );
+ if ( fgets( name, sizeof( name ), stdin ) == NULL )
+ exit( EXIT_SUCCESS );
+ name[ strlen( name ) - 1 ] = '\0';
+ if ( (p = (char *) tavl_find( tree, name, avl_strcmp ))
+ == NULL )
+ printf( "Not found.\n\n" );
+ else
+ printf( "%s\n\n", p );
+ break;
+ case 'i': /* insert */
+ printf( "data? " );
+ if ( fgets( name, sizeof( name ), stdin ) == NULL )
+ exit( EXIT_SUCCESS );
+ name[ strlen( name ) - 1 ] = '\0';
+ if ( tavl_insert( &tree, strdup( name ), avl_strcmp,
+ avl_dup_error ) != 0 )
+ printf( "\nNot inserted!\n" );
+ break;
+ case 'd': /* delete */
+ printf( "data? " );
+ if ( fgets( name, sizeof( name ), stdin ) == NULL )
+ exit( EXIT_SUCCESS );
+ name[ strlen( name ) - 1 ] = '\0';
+ if ( tavl_delete( &tree, name, avl_strcmp ) == NULL )
+ printf( "\nNot found!\n" );
+ break;
+ case 'q': /* quit */
+ exit( EXIT_SUCCESS );
+ break;
+ case '\n':
+ break;
+ default:
+ printf("Commands: insert, delete, print, new, quit\n");
+ }
+
+ printf( "> " );
+ }
+
+ return( 0 );
+}
+
+static const char bfc_array[] = "\\-/";
+static const char *bfcs = bfc_array+1;
+
+static void ravl_print( Avlnode *root, int depth, int thread )
+{
+ int i;
+
+ if ( root && !thread )
+ ravl_print( root->avl_link[1], depth+1, root->avl_bits[1] == AVL_THREAD );
+
+ for ( i = 0; i < depth; i++ )
+ printf( " " );
+ if ( thread )
+ printf( "~" );
+ else if ( root )
+ printf( "%c", bfcs[root->avl_bf] );
+ else
+ printf( " " );
+ if ( !root) {
+ printf( ".\n" );
+ return;
+ }
+ printf( "%s\n", (char *) root->avl_data );
+
+ if ( !thread )
+ ravl_print( root->avl_link[0], depth+1, root->avl_bits[0] == AVL_THREAD );
+}
+
+static void myprint( Avlnode *root )
+{
+ printf( "********\n" );
+
+ if ( root == 0 )
+ printf( "\tNULL\n" );
+ else
+ ravl_print( root, 0, 0 );
+
+ printf( "********\n" );
+}
+
+static int avl_strcmp( const void *s, const void *t )
+{
+ return strcmp( s, t );
+}
diff --git a/libraries/liblutil/utils.c b/libraries/liblutil/utils.c
new file mode 100644
index 0000000..699a1c9
--- /dev/null
+++ b/libraries/liblutil/utils.c
@@ -0,0 +1,987 @@
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 1998-2018 The OpenLDAP Foundation.
+ * 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 the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+
+#include "portable.h"
+
+#include <limits.h>
+#include <stdio.h>
+#include <ac/stdlib.h>
+#include <ac/stdarg.h>
+#include <ac/string.h>
+#include <ac/ctype.h>
+#include <ac/unistd.h>
+#include <ac/time.h>
+#include <ac/errno.h>
+#ifdef HAVE_IO_H
+#include <io.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
+#include "lutil.h"
+#include "ldap_defaults.h"
+#include "ldap_pvt.h"
+#include "lber_pvt.h"
+
+#ifdef HAVE_EBCDIC
+int _trans_argv = 1;
+#endif
+
+#ifdef _WIN32
+/* Some Windows versions accept both forward and backslashes in
+ * directory paths, but we always use backslashes when generating
+ * and parsing...
+ */
+void lutil_slashpath( char *path )
+{
+ char *c, *p;
+
+ p = path;
+ while (( c=strchr( p, '/' ))) {
+ *c++ = '\\';
+ p = c;
+ }
+}
+#endif
+
+char* lutil_progname( const char* name, int argc, char *argv[] )
+{
+ char *progname;
+
+ if(argc == 0) {
+ return (char *)name;
+ }
+
+#ifdef HAVE_EBCDIC
+ if (_trans_argv) {
+ int i;
+ for (i=0; i<argc; i++) __etoa(argv[i]);
+ _trans_argv = 0;
+ }
+#endif
+ LUTIL_SLASHPATH( argv[0] );
+ progname = strrchr ( argv[0], *LDAP_DIRSEP );
+ progname = progname ? &progname[1] : argv[0];
+#ifdef _WIN32
+ {
+ size_t len = strlen( progname );
+ if ( len > 4 && strcasecmp( &progname[len - 4], ".exe" ) == 0 )
+ progname[len - 4] = '\0';
+ }
+#endif
+ return progname;
+}
+
+#if 0
+size_t lutil_gentime( char *s, size_t smax, const struct tm *tm )
+{
+ size_t ret;
+#ifdef HAVE_EBCDIC
+/* We've been compiling in ASCII so far, but we want EBCDIC now since
+ * strftime only understands EBCDIC input.
+ */
+#pragma convlit(suspend)
+#endif
+ ret = strftime( s, smax, "%Y%m%d%H%M%SZ", tm );
+#ifdef HAVE_EBCDIC
+#pragma convlit(resume)
+ __etoa( s );
+#endif
+ return ret;
+}
+#endif
+
+size_t lutil_localtime( char *s, size_t smax, const struct tm *tm, long delta )
+{
+ size_t ret;
+ char *p;
+
+ if ( smax < 16 ) { /* YYYYmmddHHMMSSZ */
+ return 0;
+ }
+
+#ifdef HAVE_EBCDIC
+/* We've been compiling in ASCII so far, but we want EBCDIC now since
+ * strftime only understands EBCDIC input.
+ */
+#pragma convlit(suspend)
+#endif
+ ret = strftime( s, smax, "%Y%m%d%H%M%SZ", tm );
+#ifdef HAVE_EBCDIC
+#pragma convlit(resume)
+ __etoa( s );
+#endif
+ if ( delta == 0 || ret == 0 ) {
+ return ret;
+ }
+
+ if ( smax < 20 ) { /* YYYYmmddHHMMSS+HHMM */
+ return 0;
+ }
+
+ p = s + 14;
+
+ if ( delta < 0 ) {
+ p[ 0 ] = '-';
+ delta = -delta;
+ } else {
+ p[ 0 ] = '+';
+ }
+ p++;
+
+ snprintf( p, smax - 15, "%02ld%02ld", delta / 3600,
+ ( delta % 3600 ) / 60 );
+
+ return ret + 4;
+}
+
+int lutil_tm2time( struct lutil_tm *tm, struct lutil_timet *tt )
+{
+ static int moffset[12] = {
+ 0, 31, 59, 90, 120,
+ 151, 181, 212, 243,
+ 273, 304, 334 };
+ int sec;
+
+ tt->tt_usec = tm->tm_usec;
+
+ /* special case 0000/01/01+00:00:00 is returned as zero */
+ if ( tm->tm_year == -1900 && tm->tm_mon == 0 && tm->tm_mday == 1 &&
+ tm->tm_hour == 0 && tm->tm_min == 0 && tm->tm_sec == 0 ) {
+ tt->tt_sec = 0;
+ tt->tt_gsec = 0;
+ return 0;
+ }
+
+ /* tm->tm_year is years since 1900 */
+ /* calculate days from years since 1970 (epoch) */
+ tt->tt_sec = tm->tm_year - 70;
+ tt->tt_sec *= 365L;
+
+ /* count leap days in preceding years */
+ tt->tt_sec += ((tm->tm_year -69) >> 2);
+
+ /* calculate days from months */
+ tt->tt_sec += moffset[tm->tm_mon];
+
+ /* add in this year's leap day, if any */
+ if (((tm->tm_year & 3) == 0) && (tm->tm_mon > 1)) {
+ tt->tt_sec ++;
+ }
+
+ /* add in days in this month */
+ tt->tt_sec += (tm->tm_mday - 1);
+
+ /* this function can handle a range of about 17408 years... */
+ /* 86400 seconds in a day, divided by 128 = 675 */
+ tt->tt_sec *= 675;
+
+ /* move high 7 bits into tt_gsec */
+ tt->tt_gsec = tt->tt_sec >> 25;
+ tt->tt_sec -= tt->tt_gsec << 25;
+
+ /* get hours */
+ sec = tm->tm_hour;
+
+ /* convert to minutes */
+ sec *= 60L;
+ sec += tm->tm_min;
+
+ /* convert to seconds */
+ sec *= 60L;
+ sec += tm->tm_sec;
+
+ /* add remaining seconds */
+ tt->tt_sec <<= 7;
+ tt->tt_sec += sec;
+
+ /* return success */
+ return 0;
+}
+
+int lutil_parsetime( char *atm, struct lutil_tm *tm )
+{
+ while (atm && tm) {
+ char *ptr = atm;
+ unsigned i, fracs;
+
+ /* Is the stamp reasonably long? */
+ for (i=0; isdigit((unsigned char) atm[i]); i++);
+ if (i < sizeof("00000101000000")-1)
+ break;
+
+ /*
+ * parse the time into a struct tm
+ */
+ /* 4 digit year to year - 1900 */
+ tm->tm_year = *ptr++ - '0';
+ tm->tm_year *= 10; tm->tm_year += *ptr++ - '0';
+ tm->tm_year *= 10; tm->tm_year += *ptr++ - '0';
+ tm->tm_year *= 10; tm->tm_year += *ptr++ - '0';
+ tm->tm_year -= 1900;
+ /* month 01-12 to 0-11 */
+ tm->tm_mon = *ptr++ - '0';
+ tm->tm_mon *=10; tm->tm_mon += *ptr++ - '0';
+ if (tm->tm_mon < 1 || tm->tm_mon > 12) break;
+ tm->tm_mon--;
+
+ /* day of month 01-31 */
+ tm->tm_mday = *ptr++ - '0';
+ tm->tm_mday *=10; tm->tm_mday += *ptr++ - '0';
+ if (tm->tm_mday < 1 || tm->tm_mday > 31) break;
+
+ /* Hour 00-23 */
+ tm->tm_hour = *ptr++ - '0';
+ tm->tm_hour *=10; tm->tm_hour += *ptr++ - '0';
+ if (tm->tm_hour < 0 || tm->tm_hour > 23) break;
+
+ /* Minute 00-59 */
+ tm->tm_min = *ptr++ - '0';
+ tm->tm_min *=10; tm->tm_min += *ptr++ - '0';
+ if (tm->tm_min < 0 || tm->tm_min > 59) break;
+
+ /* Second 00-61 */
+ tm->tm_sec = *ptr++ - '0';
+ tm->tm_sec *=10; tm->tm_sec += *ptr++ - '0';
+ if (tm->tm_sec < 0 || tm->tm_sec > 61) break;
+
+ /* Fractions of seconds */
+ if ( *ptr == '.' ) {
+ ptr++;
+ for (i = 0, fracs = 0; isdigit((unsigned char) *ptr); ) {
+ i*=10; i+= *ptr++ - '0';
+ fracs++;
+ }
+ tm->tm_usec = i;
+ if (i) {
+ for (i = fracs; i<6; i++)
+ tm->tm_usec *= 10;
+ }
+ }
+
+ /* Must be UTC */
+ if (*ptr != 'Z') break;
+
+ return 0;
+ }
+ return -1;
+}
+
+/* strcopy is like strcpy except it returns a pointer to the trailing NUL of
+ * the result string. This allows fast construction of catenated strings
+ * without the overhead of strlen/strcat.
+ */
+char *
+lutil_strcopy(
+ char *a,
+ const char *b
+)
+{
+ if (!a || !b)
+ return a;
+
+ while ((*a++ = *b++)) ;
+ return a-1;
+}
+
+/* strncopy is like strcpy except it returns a pointer to the trailing NUL of
+ * the result string. This allows fast construction of catenated strings
+ * without the overhead of strlen/strcat.
+ */
+char *
+lutil_strncopy(
+ char *a,
+ const char *b,
+ size_t n
+)
+{
+ if (!a || !b || n == 0)
+ return a;
+
+ while ((*a++ = *b++) && n-- > 0) ;
+ return a-1;
+}
+
+/* memcopy is like memcpy except it returns a pointer to the byte past
+ * the end of the result buffer, set to NULL. This allows fast construction
+ * of catenated buffers. Provided for API consistency with lutil_str*copy().
+ */
+char *
+lutil_memcopy(
+ char *a,
+ const char *b,
+ size_t n
+)
+{
+ AC_MEMCPY(a, b, n);
+ return a + n;
+}
+
+#ifndef HAVE_MKSTEMP
+int mkstemp( char * template )
+{
+#ifdef HAVE_MKTEMP
+ return open ( mktemp ( template ), O_RDWR|O_CREAT|O_EXCL, 0600 );
+#else
+ return -1;
+#endif
+}
+#endif
+
+#ifdef _MSC_VER
+/* Equivalent of MS CRT's _dosmaperr().
+ * @param lastError[in] Result of GetLastError().
+ */
+static errno_t win2errno(DWORD lastError)
+{
+ const struct {
+ DWORD windows_code;
+ errno_t errno_code;
+ } WIN2ERRNO_TABLE[] = {
+ { ERROR_SUCCESS, 0 },
+ { ERROR_FILE_NOT_FOUND, ENOENT },
+ { ERROR_PATH_NOT_FOUND, ENOENT },
+ { ERROR_TOO_MANY_OPEN_FILES, EMFILE },
+ { ERROR_ACCESS_DENIED, EACCES },
+ { ERROR_INVALID_HANDLE, EBADF },
+ { ERROR_NOT_ENOUGH_MEMORY, ENOMEM },
+ { ERROR_LOCK_VIOLATION, EACCES },
+ { ERROR_FILE_EXISTS, EEXIST },
+ { ERROR_INVALID_PARAMETER, EINVAL },
+ { ERROR_FILENAME_EXCED_RANGE, ENAMETOOLONG },
+ };
+ const unsigned int WIN2ERRNO_TABLE_SIZE = sizeof(WIN2ERRNO_TABLE) /
+sizeof(WIN2ERRNO_TABLE[0]);
+ const errno_t DEFAULT_ERRNO_ERROR = -1;
+ unsigned int i;
+
+ for (i = 0; i < WIN2ERRNO_TABLE_SIZE; ++i) {
+ if (WIN2ERRNO_TABLE[i].windows_code == lastError) {
+ return WIN2ERRNO_TABLE[i].errno_code;
+ }
+ }
+ return DEFAULT_ERRNO_ERROR;
+}
+
+struct dirent {
+ char *d_name;
+};
+typedef struct DIR {
+ HANDLE dir;
+ struct dirent data;
+ int first;
+ char buf[MAX_PATH+1];
+} DIR;
+DIR *opendir( char *path )
+{
+ char tmp[32768];
+ int len = strlen(path);
+ DIR *d;
+ HANDLE h;
+ WIN32_FIND_DATA data;
+
+ if (len+3 >= sizeof(tmp)) {
+ errno = ENAMETOOLONG;
+ return NULL;
+ }
+
+ strcpy(tmp, path);
+ tmp[len++] = '\\';
+ tmp[len++] = '*';
+ tmp[len] = '\0';
+
+ h = FindFirstFile( tmp, &data );
+
+ if ( h == INVALID_HANDLE_VALUE ) {
+ errno = win2errno( GetLastError());
+ return NULL;
+ }
+
+ d = ber_memalloc( sizeof(DIR) );
+ if ( !d )
+ return NULL;
+ d->dir = h;
+ d->data.d_name = d->buf;
+ d->first = 1;
+ strcpy(d->data.d_name, data.cFileName);
+ return d;
+}
+struct dirent *readdir(DIR *dir)
+{
+ WIN32_FIND_DATA data;
+
+ if (dir->first) {
+ dir->first = 0;
+ } else {
+ if (!FindNextFile(dir->dir, &data))
+ return NULL;
+ strcpy(dir->data.d_name, data.cFileName);
+ }
+ return &dir->data;
+}
+int closedir(DIR *dir)
+{
+ (void) FindClose(dir->dir);
+ ber_memfree(dir);
+ return 0;
+}
+#endif
+
+/*
+ * Memory Reverse Search
+ */
+void *
+(lutil_memrchr)(const void *b, int c, size_t n)
+{
+ if (n != 0) {
+ const unsigned char *s, *bb = b, cc = c;
+
+ for ( s = bb + n; s > bb; ) {
+ if ( *--s == cc ) {
+ return (void *) s;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+int
+lutil_atoix( int *v, const char *s, int x )
+{
+ char *next;
+ long i;
+
+ assert( s != NULL );
+ assert( v != NULL );
+
+ i = strtol( s, &next, x );
+ if ( next == s || next[ 0 ] != '\0' ) {
+ return -1;
+ }
+
+ if ( (long)(int)i != i ) {
+ return 1;
+ }
+
+ *v = (int)i;
+
+ return 0;
+}
+
+int
+lutil_atoux( unsigned *v, const char *s, int x )
+{
+ char *next;
+ unsigned long u;
+
+ assert( s != NULL );
+ assert( v != NULL );
+
+ /* strtoul() has an odd interface */
+ if ( s[ 0 ] == '-' ) {
+ return -1;
+ }
+
+ u = strtoul( s, &next, x );
+ if ( next == s || next[ 0 ] != '\0' ) {
+ return -1;
+ }
+
+ if ( (unsigned long)(unsigned)u != u ) {
+ return 1;
+ }
+
+ *v = u;
+
+ return 0;
+}
+
+int
+lutil_atolx( long *v, const char *s, int x )
+{
+ char *next;
+ long l;
+ int save_errno;
+
+ assert( s != NULL );
+ assert( v != NULL );
+
+ if ( isspace( s[ 0 ] ) ) {
+ return -1;
+ }
+
+ errno = 0;
+ l = strtol( s, &next, x );
+ save_errno = errno;
+ if ( next == s || next[ 0 ] != '\0' ) {
+ return -1;
+ }
+
+ if ( ( l == LONG_MIN || l == LONG_MAX ) && save_errno != 0 ) {
+ return -1;
+ }
+
+ *v = l;
+
+ return 0;
+}
+
+int
+lutil_atoulx( unsigned long *v, const char *s, int x )
+{
+ char *next;
+ unsigned long ul;
+ int save_errno;
+
+ assert( s != NULL );
+ assert( v != NULL );
+
+ /* strtoul() has an odd interface */
+ if ( s[ 0 ] == '-' || isspace( s[ 0 ] ) ) {
+ return -1;
+ }
+
+ errno = 0;
+ ul = strtoul( s, &next, x );
+ save_errno = errno;
+ if ( next == s || next[ 0 ] != '\0' ) {
+ return -1;
+ }
+
+ if ( ( ul == 0 || ul == ULONG_MAX ) && save_errno != 0 ) {
+ return -1;
+ }
+
+ *v = ul;
+
+ return 0;
+}
+
+#ifdef HAVE_LONG_LONG
+#if defined(HAVE_STRTOLL) || defined(HAVE_STRTOQ)
+int
+lutil_atollx( long long *v, const char *s, int x )
+{
+ char *next;
+ long long ll;
+ int save_errno;
+
+ assert( s != NULL );
+ assert( v != NULL );
+
+ if ( isspace( s[ 0 ] ) ) {
+ return -1;
+ }
+
+ errno = 0;
+#ifdef HAVE_STRTOLL
+ ll = strtoll( s, &next, x );
+#else /* HAVE_STRTOQ */
+ ll = (unsigned long long)strtoq( s, &next, x );
+#endif /* HAVE_STRTOQ */
+ save_errno = errno;
+ if ( next == s || next[ 0 ] != '\0' ) {
+ return -1;
+ }
+
+ /* LLONG_MIN, LLONG_MAX are C99 only */
+#if defined (LLONG_MIN) && defined(LLONG_MAX)
+ if ( ( ll == LLONG_MIN || ll == LLONG_MAX ) && save_errno != 0 ) {
+ return -1;
+ }
+#endif /* LLONG_MIN && LLONG_MAX */
+
+ *v = ll;
+
+ return 0;
+}
+#endif /* HAVE_STRTOLL || HAVE_STRTOQ */
+
+#if defined(HAVE_STRTOULL) || defined(HAVE_STRTOUQ)
+int
+lutil_atoullx( unsigned long long *v, const char *s, int x )
+{
+ char *next;
+ unsigned long long ull;
+ int save_errno;
+
+ assert( s != NULL );
+ assert( v != NULL );
+
+ /* strtoull() has an odd interface */
+ if ( s[ 0 ] == '-' || isspace( s[ 0 ] ) ) {
+ return -1;
+ }
+
+ errno = 0;
+#ifdef HAVE_STRTOULL
+ ull = strtoull( s, &next, x );
+#else /* HAVE_STRTOUQ */
+ ull = (unsigned long long)strtouq( s, &next, x );
+#endif /* HAVE_STRTOUQ */
+ save_errno = errno;
+ if ( next == s || next[ 0 ] != '\0' ) {
+ return -1;
+ }
+
+ /* ULLONG_MAX is C99 only */
+#if defined(ULLONG_MAX)
+ if ( ( ull == 0 || ull == ULLONG_MAX ) && save_errno != 0 ) {
+ return -1;
+ }
+#endif /* ULLONG_MAX */
+
+ *v = ull;
+
+ return 0;
+}
+#endif /* HAVE_STRTOULL || HAVE_STRTOUQ */
+#endif /* HAVE_LONG_LONG */
+
+/* Multiply an integer by 100000000 and add new */
+typedef struct lutil_int_decnum {
+ unsigned char *buf;
+ int bufsiz;
+ int beg;
+ int len;
+} lutil_int_decnum;
+
+#define FACTOR1 (100000000&0xffff)
+#define FACTOR2 (100000000>>16)
+
+static void
+scale( int new, lutil_int_decnum *prev, unsigned char *tmp )
+{
+ int i, j;
+ unsigned char *in = prev->buf+prev->beg;
+ unsigned int part;
+ unsigned char *out = tmp + prev->bufsiz - prev->len;
+
+ memset( tmp, 0, prev->bufsiz );
+ if ( prev->len ) {
+ for ( i = prev->len-1; i>=0; i-- ) {
+ part = in[i] * FACTOR1;
+ for ( j = i; part; j-- ) {
+ part += out[j];
+ out[j] = part & 0xff;
+ part >>= 8;
+ }
+ part = in[i] * FACTOR2;
+ for ( j = i-2; part; j-- ) {
+ part += out[j];
+ out[j] = part & 0xff;
+ part >>= 8;
+ }
+ }
+ j++;
+ prev->beg += j;
+ prev->len -= j;
+ }
+
+ out = tmp + prev->bufsiz;
+ i = 0;
+ do {
+ i--;
+ new += out[i];
+ out[i] = new & 0xff;
+ new >>= 8;
+ } while ( new );
+ i = -i;
+ if ( prev->len < i ) {
+ prev->beg = prev->bufsiz - i;
+ prev->len = i;
+ }
+ AC_MEMCPY( prev->buf+prev->beg, tmp+prev->beg, prev->len );
+}
+
+/* Convert unlimited length decimal or hex string to binary.
+ * Output buffer must be provided, bv_len must indicate buffer size
+ * Hex input can be "0x1234" or "'1234'H"
+ *
+ * Note: High bit of binary form is always the sign bit. If the number
+ * is supposed to be positive but has the high bit set, a zero byte
+ * is prepended. It is assumed that this has already been handled on
+ * any hex input.
+ */
+int
+lutil_str2bin( struct berval *in, struct berval *out, void *ctx )
+{
+ char *pin, *pout;
+ char *end;
+ int i, chunk, len, rc = 0, hex = 0;
+ if ( !out || !out->bv_val || out->bv_len < in->bv_len )
+ return -1;
+
+ pout = out->bv_val;
+ /* Leading "0x" for hex input */
+ if ( in->bv_len > 2 && in->bv_val[0] == '0' &&
+ ( in->bv_val[1] == 'x' || in->bv_val[1] == 'X' ) )
+ {
+ len = in->bv_len - 2;
+ pin = in->bv_val + 2;
+ hex = 1;
+ } else if ( in->bv_len > 3 && in->bv_val[0] == '\'' &&
+ in->bv_val[in->bv_len-2] == '\'' &&
+ in->bv_val[in->bv_len-1] == 'H' )
+ {
+ len = in->bv_len - 3;
+ pin = in->bv_val + 1;
+ hex = 1;
+ }
+ if ( hex ) {
+#define HEXMAX (2 * sizeof(long))
+ unsigned long l;
+ char tbuf[HEXMAX+1];
+
+ /* Convert a longword at a time, but handle leading
+ * odd bytes first
+ */
+ chunk = len % HEXMAX;
+ if ( !chunk )
+ chunk = HEXMAX;
+
+ while ( len ) {
+ int ochunk;
+ memcpy( tbuf, pin, chunk );
+ tbuf[chunk] = '\0';
+ errno = 0;
+ l = strtoul( tbuf, &end, 16 );
+ if ( errno )
+ return -1;
+ ochunk = (chunk + 1)/2;
+ for ( i = ochunk - 1; i >= 0; i-- ) {
+ pout[i] = l & 0xff;
+ l >>= 8;
+ }
+ pin += chunk;
+ pout += ochunk;
+ len -= chunk;
+ chunk = HEXMAX;
+ }
+ out->bv_len = pout - out->bv_val;
+ } else {
+ /* Decimal */
+#define DECMAX 8 /* 8 digits at a time */
+ char tmpbuf[64], *tmp;
+ lutil_int_decnum num;
+ int neg = 0;
+ long l;
+ char tbuf[DECMAX+1];
+
+ len = in->bv_len;
+ pin = in->bv_val;
+ num.buf = (unsigned char *)out->bv_val;
+ num.bufsiz = out->bv_len;
+ num.beg = num.bufsiz-1;
+ num.len = 0;
+ if ( pin[0] == '-' ) {
+ neg = 0xff;
+ len--;
+ pin++;
+ }
+
+ /* tmp must be at least as large as outbuf */
+ if ( out->bv_len > sizeof(tmpbuf)) {
+ tmp = ber_memalloc_x( out->bv_len, ctx );
+ } else {
+ tmp = tmpbuf;
+ }
+ chunk = len & (DECMAX-1);
+ if ( !chunk )
+ chunk = DECMAX;
+
+ while ( len ) {
+ memcpy( tbuf, pin, chunk );
+ tbuf[chunk] = '\0';
+ errno = 0;
+ l = strtol( tbuf, &end, 10 );
+ if ( errno ) {
+ rc = -1;
+ goto decfail;
+ }
+ scale( l, &num, (unsigned char *)tmp );
+ pin += chunk;
+ len -= chunk;
+ chunk = DECMAX;
+ }
+ /* Negate the result */
+ if ( neg ) {
+ unsigned char *ptr;
+
+ ptr = num.buf+num.beg;
+
+ /* flip all bits */
+ for ( i=0; i<num.len; i++ )
+ ptr[i] ^= 0xff;
+
+ /* add 1, with carry - overflow handled below */
+ while ( i-- && ! (ptr[i] = (ptr[i] + 1) & 0xff )) ;
+ }
+ /* Prepend sign byte if wrong sign bit */
+ if (( num.buf[num.beg] ^ neg ) & 0x80 ) {
+ num.beg--;
+ num.len++;
+ num.buf[num.beg] = neg;
+ }
+ if ( num.beg )
+ AC_MEMCPY( num.buf, num.buf+num.beg, num.len );
+ out->bv_len = num.len;
+decfail:
+ if ( tmp != tmpbuf ) {
+ ber_memfree_x( tmp, ctx );
+ }
+ }
+ return rc;
+}
+
+static char time_unit[] = "dhms";
+
+/* Used to parse and unparse time intervals, not timestamps */
+int
+lutil_parse_time(
+ const char *in,
+ unsigned long *tp )
+{
+ unsigned long t = 0;
+ char *s,
+ *next;
+ int sofar = -1,
+ scale[] = { 86400, 3600, 60, 1 };
+
+ *tp = 0;
+
+ for ( s = (char *)in; s[ 0 ] != '\0'; ) {
+ unsigned long u;
+ char *what;
+
+ /* strtoul() has an odd interface */
+ if ( s[ 0 ] == '-' ) {
+ return -1;
+ }
+
+ u = strtoul( s, &next, 10 );
+ if ( next == s ) {
+ return -1;
+ }
+
+ if ( next[ 0 ] == '\0' ) {
+ /* assume seconds */
+ t += u;
+ break;
+ }
+
+ what = strchr( time_unit, next[ 0 ] );
+ if ( what == NULL ) {
+ return -1;
+ }
+
+ if ( what - time_unit <= sofar ) {
+ return -1;
+ }
+
+ sofar = what - time_unit;
+ t += u * scale[ sofar ];
+
+ s = &next[ 1 ];
+ }
+
+ *tp = t;
+ return 0;
+}
+
+int
+lutil_unparse_time(
+ char *buf,
+ size_t buflen,
+ unsigned long t )
+{
+ int len, i;
+ unsigned long v[ 4 ];
+ char *ptr = buf;
+
+ v[ 0 ] = t/86400;
+ v[ 1 ] = (t%86400)/3600;
+ v[ 2 ] = (t%3600)/60;
+ v[ 3 ] = t%60;
+
+ for ( i = 0; i < 4; i++ ) {
+ if ( v[i] > 0 || ( i == 3 && ptr == buf ) ) {
+ len = snprintf( ptr, buflen, "%lu%c", v[ i ], time_unit[ i ] );
+ if ( len < 0 || (unsigned)len >= buflen ) {
+ return -1;
+ }
+ buflen -= len;
+ ptr += len;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * formatted print to string
+ *
+ * - if return code < 0, the error code returned by vsnprintf(3) is returned
+ *
+ * - if return code > 0, the buffer was not long enough;
+ * - if next is not NULL, *next will be set to buf + bufsize - 1
+ * - if len is not NULL, *len will contain the required buffer length
+ *
+ * - if return code == 0, the buffer was long enough;
+ * - if next is not NULL, *next will point to the end of the string printed so far
+ * - if len is not NULL, *len will contain the length of the string printed so far
+ */
+int
+lutil_snprintf( char *buf, ber_len_t bufsize, char **next, ber_len_t *len, LDAP_CONST char *fmt, ... )
+{
+ va_list ap;
+ int ret;
+
+ assert( buf != NULL );
+ assert( bufsize > 0 );
+ assert( fmt != NULL );
+
+ va_start( ap, fmt );
+ ret = vsnprintf( buf, bufsize, fmt, ap );
+ va_end( ap );
+
+ if ( ret < 0 ) {
+ return ret;
+ }
+
+ if ( len ) {
+ *len = ret;
+ }
+
+ if ( (unsigned) ret >= bufsize ) {
+ if ( next ) {
+ *next = &buf[ bufsize - 1 ];
+ }
+
+ return 1;
+ }
+
+ if ( next ) {
+ *next = &buf[ ret ];
+ }
+
+ return 0;
+}
+
diff --git a/libraries/liblutil/uuid.c b/libraries/liblutil/uuid.c
new file mode 100644
index 0000000..62a4e7a
--- /dev/null
+++ b/libraries/liblutil/uuid.c
@@ -0,0 +1,460 @@
+/* uuid.c -- Universally Unique Identifier routines */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2000-2018 The OpenLDAP Foundation.
+ * Portions Copyright 2000-2003 Kurt D. Zeilenga.
+ * 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 the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* Portions Copyright 2000, John E. Schimmel, All rights reserved.
+ * This software is not subject to any license of Mirapoint, Inc.
+ *
+ * This is free software; you can redistribute and use it
+ * under the same terms as OpenLDAP itself.
+ */
+/* This work was initially developed by John E. Schimmel and adapted
+ * for inclusion in OpenLDAP Software by Kurt D. Zeilenga.
+ */
+
+/*
+ * Sorry this file is so scary, but it needs to run on a wide range of
+ * platforms. The only exported routine is lutil_uuidstr() which is all
+ * that LDAP cares about. It generates a new uuid and returns it in
+ * in string form.
+ */
+#include "portable.h"
+
+#include <limits.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#include <ac/stdlib.h>
+#include <ac/string.h> /* get memcmp() */
+
+#ifdef HAVE_UUID_TO_STR
+# include <sys/uuid.h>
+#elif defined( HAVE_UUID_GENERATE )
+# include <uuid/uuid.h>
+#elif defined( _WIN32 )
+# include <rpc.h>
+#else
+# include <ac/socket.h>
+# include <ac/time.h>
+# ifdef HAVE_SYS_SYSCTL_H
+# include <net/if.h>
+# include <sys/sysctl.h>
+# include <net/route.h>
+# endif
+#endif
+
+#include <lutil.h>
+
+/* not needed for Windows */
+#if !defined(HAVE_UUID_TO_STR) && !defined(HAVE_UUID_GENERATE) && !defined(_WIN32)
+static unsigned char *
+lutil_eaddr( void )
+{
+ static unsigned char zero[6];
+ static unsigned char eaddr[6];
+
+#ifdef HAVE_SYS_SYSCTL_H
+ size_t needed;
+ int mib[6];
+ char *buf, *next, *lim;
+ struct if_msghdr *ifm;
+ struct sockaddr_dl *sdl;
+
+ if (memcmp(eaddr, zero, sizeof(eaddr))) {
+ return eaddr;
+ }
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[3] = 0;
+ mib[3] = 0;
+ mib[4] = NET_RT_IFLIST;
+ mib[5] = 0;
+
+ if (sysctl(mib, sizeof(mib), NULL, &needed, NULL, 0) < 0) {
+ return NULL;
+ }
+
+ buf = malloc(needed);
+ if( buf == NULL ) return NULL;
+
+ if (sysctl(mib, sizeof(mib), buf, &needed, NULL, 0) < 0) {
+ free(buf);
+ return NULL;
+ }
+
+ lim = buf + needed;
+ for (next = buf; next < lim; next += ifm->ifm_msglen) {
+ ifm = (struct if_msghdr *)next;
+ sdl = (struct sockaddr_dl *)(ifm + 1);
+
+ if ( sdl->sdl_family != AF_LINK || sdl->sdl_alen == 6 ) {
+ AC_MEMCPY(eaddr,
+ (unsigned char *)sdl->sdl_data + sdl->sdl_nlen,
+ sizeof(eaddr));
+ free(buf);
+ return eaddr;
+ }
+ }
+
+ free(buf);
+ return NULL;
+
+#elif defined( SIOCGIFADDR ) && defined( AFLINK )
+ char buf[sizeof(struct ifreq) * 32];
+ struct ifconf ifc;
+ struct ifreq *ifr;
+ struct sockaddr *sa;
+ struct sockaddr_dl *sdl;
+ unsigned char *p;
+ int s, i;
+
+ if (memcmp(eaddr, zero, sizeof(eaddr))) {
+ return eaddr;
+ }
+
+ s = socket( AF_INET, SOCK_DGRAM, 0 );
+ if ( s < 0 ) {
+ return NULL;
+ }
+
+ ifc.ifc_len = sizeof( buf );
+ ifc.ifc_buf = buf;
+ memset( buf, 0, sizeof( buf ) );
+
+ i = ioctl( s, SIOCGIFCONF, (char *)&ifc );
+ close( s );
+
+ if( i < 0 ) {
+ return NULL;
+ }
+
+ for ( i = 0; i < ifc.ifc_len; ) {
+ ifr = (struct ifreq *)&ifc.ifc_buf[i];
+ sa = &ifr->ifr_addr;
+
+ if ( sa->sa_len > sizeof( ifr->ifr_addr ) ) {
+ i += sizeof( ifr->ifr_name ) + sa->sa_len;
+ } else {
+ i += sizeof( *ifr );
+ }
+
+ if ( sa->sa_family != AF_LINK ) {
+ continue;
+ }
+
+ sdl = (struct sockaddr_dl *)sa;
+
+ if ( sdl->sdl_alen == 6 ) {
+ AC_MEMCPY(eaddr,
+ (unsigned char *)sdl->sdl_data + sdl->sdl_nlen,
+ sizeof(eaddr));
+ return eaddr;
+ }
+ }
+
+ return NULL;
+
+#else
+ if (memcmp(eaddr, zero, sizeof(eaddr)) == 0) {
+ /* XXX - who knows? */
+ lutil_entropy( eaddr, sizeof(eaddr) );
+ eaddr[0] |= 0x01; /* turn it into a multicast address */
+ }
+
+ return eaddr;
+#endif
+}
+
+#if (ULONG_MAX >> 31 >> 31) > 1 || defined HAVE_LONG_LONG
+
+#if (ULONG_MAX >> 31 >> 31) > 1
+ typedef unsigned long UI64;
+ /* 100 usec intervals from 10/10/1582 to 1/1/1970 */
+# define UUID_TPLUS 0x01B21DD2138140ul
+#else
+ typedef unsigned long long UI64;
+# define UUID_TPLUS 0x01B21DD2138140ull
+#endif
+
+#define high32(i) ((unsigned long) ((i) >> 32))
+#define low32(i) ((unsigned long) (i) & 0xFFFFFFFFul)
+#define set_add64(res, i) ((res) += (i))
+#define set_add64l(res, i) ((res) += (i))
+#define mul64ll(i1, i2) ((UI64) (i1) * (i2))
+
+#else /* ! (ULONG_MAX >= 64 bits || HAVE_LONG_LONG) */
+
+typedef struct {
+ unsigned long high, low;
+} UI64;
+
+static const UI64 UUID_TPLUS = { 0x01B21Dul, 0xD2138140ul };
+
+#define high32(i) ((i).high)
+#define low32(i) ((i).low)
+
+/* res += ui64 */
+#define set_add64(res, ui64) \
+{ \
+ res.high += ui64.high; \
+ res.low = (res.low + ui64.low) & 0xFFFFFFFFul; \
+ if (res.low < ui64.low) res.high++; \
+}
+
+/* res += ul32 */
+#define set_add64l(res, ul32) \
+{ \
+ res.low = (res.low + ul32) & 0xFFFFFFFFul; \
+ if (res.low < ul32) res.high++; \
+}
+
+/* compute i1 * i2 */
+static UI64
+mul64ll(unsigned long i1, unsigned long i2)
+{
+ const unsigned int high1 = (i1 >> 16), low1 = (i1 & 0xffff);
+ const unsigned int high2 = (i2 >> 16), low2 = (i2 & 0xffff);
+
+ UI64 res;
+ unsigned long tmp;
+
+ res.high = (unsigned long) high1 * high2;
+ res.low = (unsigned long) low1 * low2;
+
+ tmp = (unsigned long) low1 * high2;
+ res.high += (tmp >> 16);
+ tmp = (tmp << 16) & 0xFFFFFFFFul;
+ res.low = (res.low + tmp) & 0xFFFFFFFFul;
+ if (res.low < tmp)
+ res.high++;
+
+ tmp = (unsigned long) low2 * high1;
+ res.high += (tmp >> 16);
+ tmp = (tmp << 16) & 0xFFFFFFFFul;
+ res.low = (res.low + tmp) & 0xFFFFFFFFul;
+ if (res.low < tmp)
+ res.high++;
+
+ return res;
+}
+
+#endif /* ULONG_MAX >= 64 bits || HAVE_LONG_LONG */
+
+#endif /* !HAVE_UUID_TO_STR && !HAVE_UUID_GENERATE && !_WIN32 */
+
+/*
+** All we really care about is an ISO UUID string. The format of a UUID is:
+** field octet note
+** time_low 0-3 low field of the timestamp
+** time_mid 4-5 middle field of timestamp
+** time_hi_and_version 6-7 high field of timestamp and
+** version number
+** clock_seq_hi_and_resv 8 high field of clock sequence
+** and variant
+** clock_seq_low 9 low field of clock sequence
+** node 10-15 spacially unique identifier
+**
+** We use DCE version one, and the DCE variant. Our unique identifier is
+** the first ethernet address on the system.
+*/
+size_t
+lutil_uuidstr( char *buf, size_t len )
+{
+#ifdef HAVE_UUID_TO_STR
+ uuid_t uu = {0};
+ unsigned rc;
+ char *s;
+ size_t l;
+
+ uuid_create( &uu, &rc );
+ if ( rc != uuid_s_ok ) {
+ return 0;
+ }
+
+ uuid_to_str( &uu, &s, &rc );
+ if ( rc != uuid_s_ok ) {
+ return 0;
+ }
+
+ l = strlen( s );
+ if ( l >= len ) {
+ free( s );
+ return 0;
+ }
+
+ strncpy( buf, s, len );
+ free( s );
+
+ return l;
+
+#elif defined( HAVE_UUID_GENERATE )
+ uuid_t uu;
+
+ uuid_generate( uu );
+ uuid_unparse_lower( uu, buf );
+ return strlen( buf );
+
+#elif defined( _WIN32 )
+ UUID uuid;
+ unsigned char *uuidstr;
+ size_t uuidlen;
+
+ if( UuidCreate( &uuid ) != RPC_S_OK ) {
+ return 0;
+ }
+
+ if( UuidToString( &uuid, &uuidstr ) != RPC_S_OK ) {
+ return 0;
+ }
+
+ uuidlen = strlen( uuidstr );
+ if( uuidlen >= len ) {
+ return 0;
+ }
+
+ strncpy( buf, uuidstr, len );
+ RpcStringFree( &uuidstr );
+
+ return uuidlen;
+
+#else
+ struct timeval tv;
+ UI64 tl;
+ unsigned char *nl;
+ unsigned short t2, t3, s1;
+ unsigned long t1, tl_high;
+ unsigned int rc;
+
+ /*
+ * Theoretically we should delay if seq wraps within 100usec but for now
+ * systems are not fast enough to worry about it.
+ */
+ static int inited = 0;
+ static unsigned short seq;
+
+ if (!inited) {
+ lutil_entropy( (unsigned char *) &seq, sizeof(seq) );
+ inited++;
+ }
+
+#ifdef HAVE_GETTIMEOFDAY
+ gettimeofday( &tv, 0 );
+#else
+ time( &tv.tv_sec );
+ tv.tv_usec = 0;
+#endif
+
+ tl = mul64ll(tv.tv_sec, 10000000UL);
+ set_add64l(tl, tv.tv_usec * 10UL);
+ set_add64(tl, UUID_TPLUS);
+
+ nl = lutil_eaddr();
+
+ t1 = low32(tl); /* time_low */
+ tl_high = high32(tl);
+ t2 = tl_high & 0xffff; /* time_mid */
+ t3 = ((tl_high >> 16) & 0x0fff) | 0x1000; /* time_hi_and_version */
+ s1 = ( ++seq & 0x1fff ) | 0x8000; /* clock_seq_and_reserved */
+
+ rc = snprintf( buf, len,
+ "%08lx-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
+ t1, (unsigned) t2, (unsigned) t3, (unsigned) s1,
+ (unsigned) nl[0], (unsigned) nl[1],
+ (unsigned) nl[2], (unsigned) nl[3],
+ (unsigned) nl[4], (unsigned) nl[5] );
+
+ return rc < len ? rc : 0;
+#endif
+}
+
+int
+lutil_uuidstr_from_normalized(
+ char *uuid,
+ size_t uuidlen,
+ char *buf,
+ size_t buflen )
+{
+ unsigned char nibble;
+ int i, d = 0;
+
+ assert( uuid != NULL );
+ assert( buf != NULL );
+
+ if ( uuidlen != 16 ) return -1;
+ if ( buflen < 36 ) return -1;
+
+ for ( i = 0; i < 16; i++ ) {
+ if ( i == 4 || i == 6 || i == 8 || i == 10 ) {
+ buf[(i<<1)+d] = '-';
+ d += 1;
+ }
+
+ nibble = (uuid[i] >> 4) & 0xF;
+ if ( nibble < 10 ) {
+ buf[(i<<1)+d] = nibble + '0';
+ } else {
+ buf[(i<<1)+d] = nibble - 10 + 'a';
+ }
+
+ nibble = (uuid[i]) & 0xF;
+ if ( nibble < 10 ) {
+ buf[(i<<1)+d+1] = nibble + '0';
+ } else {
+ buf[(i<<1)+d+1] = nibble - 10 + 'a';
+ }
+ }
+
+ if ( buflen > 36 ) buf[36] = '\0';
+ return 36;
+}
+
+#ifdef TEST
+int
+main(int argc, char **argv)
+{
+ char buf1[8], buf2[64];
+
+#ifndef HAVE_UUID_TO_STR
+ unsigned char *p = lutil_eaddr();
+
+ if( p ) {
+ printf( "Ethernet Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ (unsigned) p[0], (unsigned) p[1], (unsigned) p[2],
+ (unsigned) p[3], (unsigned) p[4], (unsigned) p[5]);
+ }
+#endif
+
+ if ( lutil_uuidstr( buf1, sizeof( buf1 ) ) ) {
+ printf( "UUID: %s\n", buf1 );
+ } else {
+ fprintf( stderr, "too short: %ld\n", (long) sizeof( buf1 ) );
+ }
+
+ if ( lutil_uuidstr( buf2, sizeof( buf2 ) ) ) {
+ printf( "UUID: %s\n", buf2 );
+ } else {
+ fprintf( stderr, "too short: %ld\n", (long) sizeof( buf2 ) );
+ }
+
+ if ( lutil_uuidstr( buf2, sizeof( buf2 ) ) ) {
+ printf( "UUID: %s\n", buf2 );
+ } else {
+ fprintf( stderr, "too short: %ld\n", (long) sizeof( buf2 ) );
+ }
+
+ return 0;
+}
+#endif