This file is indexed.

preinst is in slapd 2.4.45+dfsg-1ubuntu1.

This file is a maintainer script. It is executed when installing (*inst) or removing (*rm) the package.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
#! /bin/sh

set -e

. /usr/share/debconf/confmodule

# This will be replaced with debian/slapd.scripts-common which includes
# various helper functions and $OLD_VERSION and $SLAPD_CONF
# -*- sh -*-
# This file can be included with #SCRIPTSCOMMON#


# ===== Dumping and reloading using LDIF files =========================  {{{
#
# If incompatible changes are done to the database underlying a LDAP 
# directory we need to dump the contents and reload the data into a newly
# created database after the new server was installed. The following
# functions deal with this functionality.


# ----- Configuration of this component --------------------------------  {{{
#
# Dumping the database can have negative effects on the system we are
# running on. If there is a lot of data dumping it might fill a partition
# for example. Therefore we must give the user exact control over what we
# are doing.

database_dumping_enabled() {						# {{{
# Check if the user has enabled database dumping for the current situation.
# Return success if yes.
# Usage: if database_dumping_enabled; then ... fi

	# If the package is being removed, dump unconditionally as we
	# don't know whether the next version will require reload.
	[ "$MODE" = remove ] && return 0

	db_get slapd/dump_database
	case "$RET" in
	always)
		;;
	"when needed")
		database_format_changed || return 1
		;;
	never)
		return 1
		;;
	*)
		echo >&2 "Unknown value for slapd/dump_database: $RET"
		echo >&2 "Please report!"
		exit 1
		;;
	esac
}

# }}}
database_format_changed() {						# {{{
# Check if the database format has changed since the old installed version
# Return success if yes.
# Usage: if database_format_changed; then

	if dpkg --compare-versions "$OLD_VERSION" lt-nl 2.4.39-1; then
		return 0
	else
		return 1
	fi
}

# }}}
database_dumping_destdir() {						# {{{
# Figure out the directory we are dumping the database to and create it
# if it does not exist.
# Usage: destdir=`database_dumping_destdir`

	local dir
	db_get slapd/dump_database_destdir
	dir=`echo "$RET"|sed -e "s/VERSION/$OLD_VERSION/"`
	mkdir -p -m 700 "$dir"
	echo $dir
}

# }}}
create_new_user() { # {{{
	if [ -z "`getent group openldap`" ]; then
		addgroup --quiet --system openldap
	fi
	if [ -z "`getent passwd openldap`" ]; then
		echo -n "  Creating new user openldap... " >&2
		adduser --quiet --system --home /var/lib/ldap --shell /bin/false \
			--ingroup openldap --disabled-password --disabled-login \
			--gecos "OpenLDAP Server Account" openldap
		echo "done." >&2
	fi
}
# }}}
create_ldap_directories() {	# {{{
	if [ ! -d /var/lib/ldap ]; then
		mkdir -m 0700 /var/lib/ldap
	fi
	if [ ! -d /var/run/slapd ]; then
		mkdir -m 0755 /var/run/slapd
	fi
	update_permissions /var/lib/ldap
	update_permissions /var/run/slapd
}
# }}}
update_permissions() {	# {{{
	local dir
	dir="$1"
	if [ -d "$dir" ]; then
		[ -z "$SLAPD_USER" ] || chown -R -H "$SLAPD_USER" "$dir"
		[ -z "$SLAPD_GROUP" ] || chgrp -R -H "$SLAPD_GROUP" "$dir"
	fi
}
# }}}
update_databases_permissions() {	# {{{
	get_suffix | while read -r suffix; do
		dbdir=`get_directory "$suffix"`
		update_permissions "$dbdir"
	done
}
# }}}
# }}}
# ----- Dumping and loading the data ------------------------------------ {{{

migrate_to_slapd_d_style() {				# {{{

	# Check if we need to migrate to the new style.
	if previous_version_older 2.4.23-3 && [ -f "${SLAPD_CONF}" ] \
	   && ! [ -d /etc/ldap/slapd.d ]
	then

		# Create the new configuration directory
		mkdir /etc/ldap/slapd.d

		echo -n "  Migrating slapd.conf to slapd.d configuration style... " >&2
		capture_diagnostics slaptest -f ${SLAPD_CONF} -F /etc/ldap/slapd.d || failed=1
		if [ "$failed" ]; then

			echo "failed." >&2
			echo >&2
			cat <<-EOF
Migrating slapd.conf file (${SLAPD_CONF}) to slapd.d failed with the following
error while running slaptest:
EOF
			release_diagnostics "    "
			rm -rf /etc/ldap/slapd.d
			exit 1
		fi

		# Backup the old slapd.conf
		mv ${SLAPD_CONF} ${SLAPD_CONF}.old
		SLAPD_CONF=/etc/ldap/slapd.d

		# Add olcAccess control to grant local root connections access
		sed -i '/^olcDatabase: {-1}frontend/a\
olcAccess: {0}to * by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage by * break\
olcAccess: {1}to dn.exact="" by * read\
olcAccess: {2}to dn.base="cn=Subschema" by * read' "${SLAPD_CONF}/cn=config/olcDatabase={-1}frontend.ldif"
		sed -i '/^olcDatabase: {0}config/a\
olcAccess: {0}to * by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage by * break' "${SLAPD_CONF}/cn=config/olcDatabase={0}config.ldif"

		# TODO: Now we are doing something that is not allowed by policy but it
		# has to be done.
		sed -i -e "/^[[:space:]]*SLAPD_CONF=.*/ s/^/#/" /etc/default/slapd
		echo "done." >&2
	fi
}

# }}}
dump_config() {								# {{{
# Dump the cn=config database to the backup directory.
# This is not the same as backup_config_once, which copies the slapd.d 
# directory verbatim.
	local dir

	[ -d "$SLAPD_CONF" ] || return 0

	dir="$(database_dumping_destdir)"
	echo "Saving current slapd configuration to $dir..." >&2
	slapcat -F "$SLAPD_CONF" -n0 -l "$dir/cn=config.ldif"
}
# }}}
dump_databases() {							# {{{
# If the user wants us to dump the databases they are dumped to the 
# configured directory.
	local db suffix file dir failed slapcat_opts

	database_dumping_enabled || return 0

	dir=`database_dumping_destdir`
	echo >&2 "  Dumping to $dir: "
	(get_suffix | while read suffix; do
		dbdir=`get_directory "$suffix"`
		if [ -n "$dbdir" ]; then
			file="$dir/$suffix.ldif"
			echo -n "  - directory $suffix... " >&2
			# Need to support slapd.d migration from preinst
			if [ -f "${SLAPD_CONF}" ]; then
				slapcat_opts="-g -f ${SLAPD_CONF}"
			else
				slapcat_opts="-g -F ${SLAPD_CONF}"
			fi
			slapcat ${slapcat_opts} -b "$suffix" > "$file" || failed=1
			if [ "$failed" ]; then
				rm -f "$file"
				echo "failed." >&2
				db_subst slapd/upgrade_slapcat_failure location "$dir" <&5
				db_input critical slapd/upgrade_slapcat_failure <&5 || true
				db_go <&5 || true
				exit 1
			fi
			echo "done." >&2
		fi
	done) 5<&0 </dev/null
}

# }}}
load_databases() {							# {{{
	local dir file db dbdir backupdir slapadd_opts

	dir=`database_dumping_destdir`
	echo >&2 "  Loading from $dir: "
	# restore by increasing suffix length due to possibly glued databases
	get_suffix | awk '{ print length, $0 }' | sort -n | cut -d ' ' -f 2- \
	| while read suffix; do
		dbdir=`get_directory "$suffix"`
		if [ -z "$dbdir" ]; then
			continue
		fi
		if ! is_empty_dir "$dbdir"; then
			echo >&2 \
			  "  Directory $dbdir for $suffix not empty, aborting."
			exit 1
		fi

		file="$dir/$suffix.ldif"
		echo -n "  - directory $suffix... " >&2

		# If there is an old DB_CONFIG file, restore it before
		# running slapadd
		backupdir=`compute_backup_path -n "$dbdir" "$suffix"`
		if [ -e "$backupdir"/DB_CONFIG ]; then
			cp -a "$backupdir"/DB_CONFIG "$dbdir"/
		fi

		if [ -f "${SLAPD_CONF}" ]; then
			slapadd_opts="-g -f ${SLAPD_CONF}"
		else
			slapadd_opts="-g -F ${SLAPD_CONF}"
		fi
		capture_diagnostics slapadd ${slapadd_opts} \
			-q -b "$suffix" -l "$file" || failed=1
		if [ "$failed" ]; then
			rm -f "$dbdir"/*
			echo "failed." >&2
			echo >&2
			cat <<-EOF
	Loading the database from the LDIF dump failed with the following
	error while running slapadd:
EOF
			release_diagnostics "    "
			exit 1
		fi
		echo "done." >&2

		if [ -n "$SLAPD_USER" ] || [ -n "$SLAPD_GROUP" ]; then
			echo -n "  - chowning database directory ($SLAPD_USER:$SLAPD_GROUP)... "
			update_permissions "$dbdir"
			echo "done";
		fi
	done
}

# }}}
move_incompatible_databases_away() {					# {{{
	echo >&2 "  Moving old database directories to /var/backups:"
	(get_suffix | while read suffix; do
		dbdir=`get_directory "$suffix"`
		move_old_database_away "$dbdir" "$suffix" <&5
	done) 5<&0 </dev/null
}
# }}}
# }}}
# }}}

# ===== Parsing the slapd configuration file ============================ {{{
#
# For some operations we have to know the slapd configuration. These 
# functions are for parsing the slapd configuration file.

# The following two functions need to support slapd.conf installations 
# as long as upgrading from slapd.conf environment is supported.
# They're used to dump database in preinst which may have a slapd.conf file.
get_suffix() {								# {{{
	if [ -f "${SLAPD_CONF}" ]; then
		for f in `get_all_slapd_conf_files`; do
			sed -n -e's/^suffix[[:space:]]\+"*\([^"]\+\)"*/\1/p' $f
		done
	else
		grep -h ^olcSuffix ${SLAPD_CONF}/cn\=config/olcDatabase*.ldif | cut -d: -f 2
	fi | sort -u
}
# }}}
get_directory() {							# {{{
# Returns the db directory for a given suffix
	if [ -d "${SLAPD_CONF}" ] && get_suffix | grep -Fq "$1" ; then
		sed -n 's/^olcDbDirectory: *//p' `grep -Fl "^olcSuffix: $1" ${SLAPD_CONF}/cn\=config/olcDatabase*.ldif`
	elif [ -f "${SLAPD_CONF}" ]; then
		# Extract the directory for the given suffix ($1)
		for f in `get_all_slapd_conf_files`; do
		awk  ' BEGIN { DB=0; SUF=""; DIR="" } ;
		       /^database/ { DB=1; SUF=""; DIR="" } ; 
		       DB==1 && /^suffix[ \t]+"?'"$1"'"?$/ { SUF=$2 ; } ; 
		       DB==1 && /^directory/ { DIR=$2 ;} ; 
		       DB==1 && SUF!="" && DIR!="" { sub(/^"/,"",DIR) ; sub(/"$/,"",DIR) ; print DIR; SUF=""; DIR="" }' "${f}" | \
		sed -e's/\([^\\]\|^\)"/\1/g; s/\\"/"/g; s/\\\\/\\/g'

		done
	else
		return 1
	fi
}
# }}}
get_all_slapd_conf_files() {						# {{{
# Returns the list of all the config files: slapd.conf and included files.
	echo ${SLAPD_CONF}
	awk '
BEGIN { I=0 } 
/^include/ {
	sub(/include/," ");
	I=1;
} 
I==1 && /^[ \t]+/ { 
	split($0,F) ;
	for (f in F) 
		if (!match(F[f],/schema/)) { 
			print F[f]
		} ;
	next;
}
I==1 { I=0 }
' ${SLAPD_CONF}
}
# }}}
# }}}

compute_backup_path() {							# {{{
# Compute the path to backup a database directory
# Usage: compute_backup_path [-n] <dir> <basedn>

# XXX: should ask the user via debconf

	local dirname basedn ok_exists
	if [ "$1" = "-n" ]; then
		ok_exists=yes
		shift
	fi
	dirname="$1"
	basedn="$2"

	# Computing the name of the backup directory from the old version, 
	# the suffix etc. all makes me feel worried. I'd rather have a 
	# directory name which is not going to exist. So the simple 
	# scheme we are using now is to compute the filename from the 
	# directory name and appending date and time. And we check if it
	# exists to be really sure...  -- Torsten

	local target
	local id
	id="$OLD_VERSION"
	[ -n "$id" ] || id=`date +%Y%m%d-%H%M%S`
	target="/var/backups/$basedn-$id.ldapdb"
	# Configuration via dpkg-reconfigure. 
	# The backup directory already exists when reconfigured 
	# twice or more: append a timestamp.
	if [ -e "${target}" ] && ([ "$MODE" = reconfigure ] || [ "$DEBCONF_RECONFIGURE" ]); then
			 target="$target-`date +%Y%m%d-%H%M%S`"
	fi
	if [ -e "$target" ] && [ -z "$ok_exists" ]; then
		echo >&2
		echo >&2 "  Backup path $target exists. Giving up..."
		exit 1
	fi

	echo "$target"
}

# }}}
move_old_database_away() {						# {{{
# Move the old database away if it is still there
#
# In fact this function makes sure that the database directory is empty
# with the exception of any DB_CONFIG file
# and can be populated with a new database. If something is in the way
# it is moved to a backup directory if the user accepted the debconf
# option slapd/move_old_database. Otherwise we output a warning and let
# the user fix it himself.
# Usage: move_old_database_away <dbdir> [<basedn>]

	local databasedir backupdir
	databasedir="$1"
	suffix="${2:-unknown}"
	
	if [ ! -e "$databasedir" ] || is_empty_dir "$databasedir"; then
		return 0
	fi

	# Note that we can't just move the database dir as it might be
	# a mount point. Instead me move the content which might 
	# include mount points as well anyway, but it's much less likely.
	db_get slapd/move_old_database
	if [ "$RET" = true ]; then
		backupdir=`compute_backup_path "$databasedir" "$suffix"`
		echo -n "  - directory $suffix... " >&2
		mkdir -p "$backupdir"
		find -H "$databasedir" -mindepth 1 -maxdepth 1 -type f \
			-exec mv {} "$backupdir" \;
		echo done. >&2
	else
		cat >&2 <<EOF
  There are leftover files in $databasedir. This will probably break 
  creating the initial directory. If that's the case please move away
  stuff in there and retry the configuration.
EOF
	fi
}
# }}}
manual_configuration_wanted() {						# {{{
# Check if the user wants to configure everything himself (queries debconf)
# Returns success if yes.

	db_get slapd/no_configuration
	if [ "$RET" = "true" ]; then
		return 0
	else
		return 1
	fi
}
# }}}
copy_example_DB_CONFIG() {						# {{{
# Copy an example DB_CONFIG file
# copy_example_DB_CONFIG <directory>
	local directory srcdir
	
	directory="$1"
	srcdir="/usr/share/slapd"

	if ! [ -f "${directory}/DB_CONFIG" ] && [ -d "$directory" ]; then
		cp $srcdir/DB_CONFIG "${directory}/DB_CONFIG"
	fi
}

# }}}
create_new_configuration() {						# {{{
# Create a new configuration and directory

	local basedn dc backend

	# For the domain really.argh.org we create the basedn 
	# dc=really,dc=argh,dc=org with the dc entry dc: really
	db_get slapd/domain
	basedn="dc=`echo $RET | sed 's/^\.//; s/\.$//; s/\./,dc=/g'`"
	dc="`echo $RET | sed 's/^\.//; s/\..*$//'`"

	db_get slapd/backend
	backend="`echo $RET|tr A-Z a-z`"

	backup_config_once
	if [ -e "/var/lib/ldap" ] && ! is_empty_dir /var/lib/ldap; then
		echo >&2 "  Moving old database directory to /var/backups:"
		move_old_database_away /var/lib/ldap
	fi
	create_ldap_directories
	create_new_slapd_conf "$basedn" "$backend"
	create_new_directory "$basedn" "$dc"

	# Put the right permissions on this directory.
	update_permissions /var/lib/ldap

	# Now that we created the new directory we don't need the passwords in the
	# debconf database anymore. So wipe them.
	wipe_admin_pass
}
# }}}
create_new_slapd_conf() {						# {{{
# Create the new slapd.d directory (configuration)
# Usage: create_new_slapd_conf <basedn> <backend>

	local initldif failed basedn backend backendobjectclass backendoptions adminpass

	# Fetch configuration
	basedn="$1"
	backend="$2"
	if [ "$backend" = "mdb" ]; then
		backendoptions="olcDbMaxSize: 1073741824"
		backendobjectclass="olcMdbConfig"
	else
		backendoptions="olcDbConfig: set_cachesize 0 2097152 0\nolcDbConfig: set_lk_max_objects 1500\nolcDbConfig: set_lk_max_locks 1500\nolcDbConfig: set_lk_max_lockers 1500"
		if [ "$backend" = "hdb" ]; then
			backendobjectclass="olcHdbConfig"
		else
			backendobjectclass="olcBdbConfig"
		fi
	fi
	db_get slapd/internal/adminpw
	adminpass="$RET"

	echo -n "  Creating initial configuration... " >&2

	# Create the slapd.d directory.
	rm -rf ${SLAPD_CONF}/cn=config ${SLAPD_CONF}/cn=config.ldif
	mkdir -p ${SLAPD_CONF}
	initldif=`mktemp -t slapadd.XXXXXX`
	cat /usr/share/slapd/slapd.init.ldif > ${initldif}

	# Change some defaults
	sed -i -e "s|@BACKEND@|$backend|g" ${initldif}
	sed -i -e "s|@BACKENDOBJECTCLASS@|$backendobjectclass|g" ${initldif}
	sed -i -e "s|@BACKENDOPTIONS@|$backendoptions|g" ${initldif}
	sed -i -e "s|@SUFFIX@|$basedn|g" ${initldif}
	sed -i -e "s|@PASSWORD@|$adminpass|g" ${initldif}

	capture_diagnostics slapadd -F "${SLAPD_CONF}" -b "cn=config" \
		-l "${initldif}" || failed=1
	if [ "$failed" ]; then
		cat <<-EOF
Loading the initial configuration from the ldif file (${init_ldif}) failed with
the following error while running slapadd:
EOF
		release_diagnostics "    "
		exit 1
	fi

	update_permissions "${SLAPD_CONF}"
	rm -f "${initldif}"
	echo "done." >&2
}
# }}}
encode_utf8() { #{{{
# Make the value utf8 encoded. Takes one argument and utf8 encode it.
# Usage: val=`encode_utf8 <value>`
  perl -e 'use Encode; print encode_utf8($ARGV[0]);' "$1"
} #}}}
create_new_directory() {						# {{{
# Create a new directory. Takes the basedn and the dc value of that entry.
# Other information is extracted from debconf.
# Usage: create_new_directory <basedn> <dc>

	local basedn dc organization adminpass
	basedn="$1"
	dc="$2"
	
	# Encode to utf8 and base64 encode the organization.
	db_get shared/organization
	organization=`encode_utf8 "$RET"`
	db_get slapd/internal/adminpw
	adminpass="$RET"

	echo -n "  Creating LDAP directory... " >&2

	initldif=`mktemp -t slapadd.XXXXXX`
	cat <<-EOF > "${initldif}"
		dn: $basedn
		objectClass: top
		objectClass: dcObject
		objectClass: organization
		o: $organization
		dc: $dc

		dn: cn=admin,$basedn
		objectClass: simpleSecurityObject
		objectClass: organizationalRole
		cn: admin
		description: LDAP administrator
		userPassword: $adminpass
	EOF

	capture_diagnostics slapadd -F "${SLAPD_CONF}" -b "${basedn}" \
		-l "${initldif}" || failed=1
	if [ "$failed" ]; then
		rm -f ${initldif}
		echo "failed." >&2
		cat <<-EOF
Loading the initial configuration from the ldif file (${init_ldif}) failed with
the following error while running slapadd:
EOF
		release_diagnostics "    "
		exit 1
	fi

	rm -f ${initldif}
	echo "done." >&2
}
# }}}
backup_config_once() {							# {{{
# Create a backup of the current configuration files. 
# Usage: backup_config_once

	local backupdir

	if [ -z "$FLAG_CONFIG_BACKED_UP" ]; then
		if [ -e "$SLAPD_CONF" ]; then
			backupdir=`database_dumping_destdir`
			echo -n "  Backing up $SLAPD_CONF in ${backupdir}... " >&2
			cp -a "$SLAPD_CONF" "$backupdir"
			echo done. >&2
		fi
		FLAG_CONFIG_BACKED_UP=yes
	fi
}

# }}}
normalize_ldif() {							# {{{
# Unwrap LDIF lines and strip comments.
	perl -00 -pe 's/\n[ \t]//g; s/^#.*\n//mg' "$@"
}
# }}}


set_defaults_for_unseen_entries() {					# {{{
# Set up the defaults for our templates
	DOMAIN=`hostname -d 2>/dev/null` || true
	if [ -z "$DOMAIN" ]; then DOMAIN='nodomain'; fi

	db_fget slapd/domain seen
	if [ "$RET" = false ]; then
		db_set slapd/domain "$DOMAIN"
	fi

	db_fget shared/organization seen
	if [ "$RET" = false ]; then
		db_set shared/organization "$DOMAIN"
	fi
}
# }}}
crypt_admin_pass() {							# {{{
# Store the encrypted admin password into the debconf db
# Usage: crypt_admin_pass

	local adminpw;

	db_get slapd/password1
	if [ ! -z "$RET" ]; then
		db_set slapd/internal/adminpw `create_password_hash "$RET"`
	else

		# Set the password.
		adminpw=`generate_admin_pass`
		db_set slapd/internal/generated_adminpw $adminpw
		db_set slapd/internal/adminpw `create_password_hash "$adminpw"`
	fi
}

generate_admin_pass() {
# Generate a password, if no password given then generate one.
# Usage: generate_admin_pass

	perl << 'EOF'
# --------
sub generatePassword {
	$length = shift;
	$possible = 'abcdefghijklmnopqrstuvwxyz1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ';
	$password = '';
	while(length($password) < $length) {
		$password.= substr($possible, (int(rand(length($possible)))), 1);
	}
	return $password;
}
print generatePassword(15);
EOF
# --------
}

wipe_admin_pass() {
# Remove passwords after creating the initial ldap database.
# Usage: wipe_admin_pass
	db_set slapd/password1 ""
	db_set slapd/password2 ""
	db_set slapd/internal/adminpw ""
	db_set slapd/internal/generated_adminpw ""
}

# }}}
create_password_hash() {						# {{{
# Create the password hash for the given password
# Usage: hash=`create_password_hash "$password"`

	slappasswd -s "$1"
}

# }}}
previous_version_older() {						# {{{
# Check if the previous version is newer than the reference version passed.
# If we are not upgrading the previous version is assumed to be newer than
# any reference version.
# Usage: previous_version_older <package version>
	
	if dpkg --compare-versions "$OLD_VERSION" lt-nl "$1"; then
		return 0
	else
		return 1
	fi
} 

# }}}
previous_version_newer() {						# {{{
# Check if the previous version is newer than the reference version passed.
# If we are not upgrading the previous version is assumed to be newer than
# any reference version.
# Usage: previous_version_newer <package version>
	
	if dpkg --compare-versions "$OLD_VERSION" gt-nl "$1"; then
		return 0
	else
		return 1
	fi
} # }}}

is_initial_configuration() {						# {{{
# Check if this is the initial configuration and not an upgrade of an 
# existing configuration
# Usage: if is_initial_configuration "$@"; then ... fi from top level

	# Plain installation
	if [ "$1" = configure ] && [ -z "$2" ]; then
		return 0
	fi
	# Configuration via dpkg-reconfigure
	if [ "$1" = reconfigure ] || [ "$DEBCONF_RECONFIGURE" ]; then
		return 0
	fi
	# Upgrade but slapd.conf doesn't exist.  If the user is doing this
	# intentionally because they want to put it somewhere else, they
	# should select manual configuration in debconf.
	if [ "$1" = configure ] && [ ! -e "${SLAPD_CONF}" ]; then
		return 0
	fi
	return 1
}

# }}}
is_empty_dir() {							# {{{
# Check if a path refers to a directory that is "empty" from the POV of slapd
# (i.e., contains no files except for an optional DB_CONFIG).
# Usage: if is_empty_dir "$dir"; then ... fi

	output=`find -H "$1" -mindepth 1 -maxdepth 1 -type f \! -name DB_CONFIG 2>/dev/null`
	if [ -n "$output" ]; then
    		return 1
	else
		return 0
  	fi
}

# }}}

find_old_ppolicy_schema() {						# {{{
# Helper for the ppolicy schema update in 2.4.43. Checks whether the 
# exported config includes an old version of the ppolicy schema that 
# needs the new attribute added. If such a schema is found, echos its DN 
# to stdout. If the schema is not loaded or is already up-to-date, 
# returns nothing. The provided LDIF should have its lines unwrapped 
# already.
# Usage: ppolicy_dn="$(find_old_ppolicy_schema "$exported_ldif")"
	local ppolicy_dn

	# Is the ppolicy schema loaded?
	if ! ppolicy_dn="$(grep '^dn: cn={[0-9]\+}ppolicy,cn=schema,cn=config$' "$1")"; then
		return
	fi

	# Has the pwdMaxRecordedFailure attribute already been added?
	# It might have been replicated from a newer server.
	if grep -q '^olcAttributeTypes: .*NAME '\''pwdMaxRecordedFailure'\' "$1"; then
		return
	fi

	# The schema is loaded and needs to be updated.
	ppolicy_dn="${ppolicy_dn#dn: }"
	echo "$ppolicy_dn"
}
# }}}

# ===== Global variables ================================================ {{{
#
# At some points we need to know which version we are upgrading from if
# any. More precisely we only care about the configuration and data we 
# might have laying around. Some parts also want to know which mode the
# script is running in.

MODE="$1"		# install, upgrade, etc. - see debian-policy
OLD_VERSION="$2"

# Source the init script configuration
# See example file debian/slapd.default for variables defined here
if [ -f "/etc/default/slapd" ]; then
	. /etc/default/slapd
fi

# Load the default location of the slapd config file
if [ -z "$SLAPD_CONF" ]; then
	if [ -f "/etc/ldap/slapd.conf" ] && \
		[ ! -e "/etc/ldap/slapd.d" ]
	then
		SLAPD_CONF="/etc/ldap/slapd.conf"
	else
		SLAPD_CONF="/etc/ldap/slapd.d"
	fi
fi

# }}}

# ----- Handling diagnostic output ------------------------------------ {{{
#
# Often you want to run a program while you are showing progress 
# information to the user. If the program you are running outputs some 
# diagnostics it will mess up your screen. 
#
# This is what the following functions are designed for. When running the
# program, use capture_diagnostics to store what the program outputs to 
# stderr and use release_diagnostics to write out the captured output.


capture_diagnostics() {							# {{{
# Run the command passed and capture the diagnostic output in a temporary
# file. You can dump that file using release_diagnostics.

	# Create the temporary file
	local tmpfile
	tmpfile=`mktemp`
	exec 7<>"$tmpfile"
	rm "$tmpfile"

	# Run the program and capture stderr. If the program fails the 
	# function fails with the same status.
	"$@" 2>&7 || return $?
}

# }}}
release_diagnostics() {							# {{{
# Dump the diagnostic output captured via capture_diagnostics, optionally
# prefixing each line.
# Usage: release_diagnostics "prefix"

	local script
	script='
		seek STDIN, 0, 0;
		print "$ARGV[0]$_" while (<STDIN>);';
	perl -e "$script" "$1" <&7
}

# }}}


# }}}

# vim: set sw=8 foldmethod=marker: 



ppolicy_schema_needs_update() {						# {{{
# Provide an LDIF to add the pwdMaxRecordedFailure attribute to the 
# ppolicy schema, and recommend the user apply it before continuing with 
# the slapd upgrade.
	local update_ldif

	update_ldif="$(mktemp --tmpdir ppolicy-schema-update-XXXXXXXX.ldif)"
	cat > "$update_ldif" << eof
dn: $1
changetype: modify
add: olcAttributeTypes
olcAttributeTypes: {16}( 1.3.6.1.4.1.42.2.27.8.1.30 NAME 'pwdMaxRecordedFailure' EQUALITY integerMatch ORDERING integerOrderingMatch  SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
-
delete: olcObjectClasses
olcObjectClasses: {1}( 1.3.6.1.4.1.42.2.27.8.2.1 NAME 'pwdPolicy' SUP top AUXILIARY MUST pwdAttribute MAY ( pwdMinAge $ pwdMaxAge $ pwdInHistory $ pwdCheckQuality $ pwdMinLength $ pwdExpireWarning $ pwdGraceAuthNLimit $ pwdLockout $ pwdLockoutDuration $ pwdMaxFailure $ pwdFailureCountInterval $ pwdMustChange $ pwdAllowUserChange $ pwdSafeModify ) )
-
add: olcObjectClasses
olcObjectClasses: {1}( 1.3.6.1.4.1.42.2.27.8.2.1 NAME 'pwdPolicy' SUP top AUXILIARY MUST pwdAttribute MAY ( pwdMinAge $ pwdMaxAge $ pwdInHistory $ pwdCheckQuality $ pwdMinLength $ pwdExpireWarning $ pwdGraceAuthNLimit $ pwdLockout $ pwdLockoutDuration $ pwdMaxFailure $ pwdFailureCountInterval $ pwdMustChange $ pwdAllowUserChange $ pwdSafeModify $ pwdMaxRecordedFailure ) )

eof

	db_subst slapd/ppolicy_schema_needs_update ldif "$update_ldif"
	db_fset slapd/ppolicy_schema_needs_update seen false
	db_input critical slapd/ppolicy_schema_needs_update || true
	db_go || true
	db_get slapd/ppolicy_schema_needs_update
	if [ "$RET" = 'abort installation' ]; then
		db_stop
		exit 1
	fi
}
# }}}
check_ppolicy_schema() {						# {{{
# When upgrading to 2.4.43 or later, if the cn=config database contains 
# an old version of the ppolicy schema, check that it is safe to upgrade 
# it automatically in postinst, or instruct the user to do so before 
# upgrading.
	local config_ldif="$1"

	# Check whether the schema is loaded and needs an update.
	local ppolicy_dn="$(find_old_ppolicy_schema "$config_ldif")"
	if [ -z "$ppolicy_dn" ]; then
		return
	fi

	# If either the config or frontend databases have any overlays 
	# or syncrepl clients on them, don't assume it's safe to change 
	# the config offline.
	# As well, if a content database is a sync provider, we want to 
	# recommend that the schema be updated on every server before 
	# going through with the upgrade.
	if grep -q -e '^dn: olcOverlay=.\+,olcDatabase={-1}frontend,cn=config$' -e '^dn: olcOverlay=.\+,olcDatabase={0}config,cn=config$' "$config_ldif" \
		|| sed -n '/^dn: olcDatabase={-1}frontend,cn=config$/,// p' "$config_ldif" | grep -q '^olcSyncrepl:' \
		|| sed -n '/^dn: olcDatabase={0}config,cn=config$/,//p' "$config_ldif" | grep -q '^olcSyncrepl:' \
		|| grep -q '^dn: olcOverlay={[0-9]\+}syncprov,olcDatabase=.\+,cn=config' "$config_ldif"; then
		ppolicy_schema_needs_update "$ppolicy_dn"
	fi

	# If we made it this far, it should be safe to upgrade the 
	# schema automatically in postinst.
}
# }}}
preinst_check_config() {						# {{{
# Check whether manual config changes are required before upgrading
	if ! previous_version_older '2.4.44+dfsg-1~'; then
		# no pre-checks required
		return 0
	fi

	# Locate the file exported by dump_config.
	local dumped_ldif="$(database_dumping_destdir)/cn=config.ldif"
	if [ ! -f "$dumped_ldif" ]; then
		echo "Expected to find a configuration backup in $dumped_ldif but it is missing. Please retry the upgrade." >&2
		exit 1
	fi

	# Create a working copy with lines unwrapped.
	local config_ldif="$(mktemp --tmpdir slapd.XXXXXXXX.ldif)"
	trap "trap - INT EXIT; rm -f '$config_ldif'" INT EXIT
	normalize_ldif "$dumped_ldif" > "$config_ldif"

	check_ppolicy_schema "$config_ldif"
}
# }}}

# If we are upgrading from an old version then stop slapd and attempt to
# slapcat out the data so we can use it in postinst to do the upgrade.
# If slapd was removed and is being reinstalled, slapcat is not
# available at this time, so the data should have been dumped before the
# old slapd was removed.

if [ "$MODE" = upgrade ]; then
	dump_config
fi

if [ "$MODE" = upgrade ] || [ "$MODE" = install -a -n "$OLD_VERSION" ]; then
	# Do not assume slapcat is available in this phase
	if [ -d "$SLAPD_CONF" ]; then
		preinst_check_config
	fi
fi

if [ "$MODE" = upgrade ]; then
	dump_databases
fi



exit 0

# vim: set sw=8 foldmethod=marker: