--- debathena-moira-4.0.0+cvs20080304.orig/config.sub
+++ debathena-moira-4.0.0+cvs20080304/config.sub
@@ -1,6 +1,11 @@
 #! /bin/sh
-# Configuration validation subroutine script, version 1.1.
-#   Copyright (C) 1991, 92-97, 1998 Free Software Foundation, Inc.
+# Configuration validation subroutine script.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+#   Free Software Foundation, Inc.
+
+timestamp='2008-01-16'
+
 # This file is (in principle) common to ALL GNU software.
 # The presence of a machine in this file suggests that SOME GNU software
 # can handle that machine.  It does not imply ALL GNU software can.
@@ -17,14 +22,18 @@
 #
 # You should have received a copy of the GNU General Public License
 # along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330,
-# Boston, MA 02111-1307, USA.
-
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
 # As a special exception to the GNU General Public License, if you
 # distribute this file as part of a program that contains a
 # configuration script generated by Autoconf, you may include it under
 # the same distribution terms that you use for the rest of that program.
 
+
+# Please send patches to <config-patches@gnu.org>.  Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
 # Configuration subroutine to validate and canonicalize a configuration type.
 # Supply the specified configuration type as an argument.
 # If it is invalid, we print an error message on stderr and exit with code 1.
@@ -45,30 +54,75 @@
 #	CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
 # It is wrong to echo any other type of specification.
 
-if [ x$1 = x ]
-then
-	echo Configuration name missing. 1>&2
-	echo "Usage: $0 CPU-MFR-OPSYS" 1>&2
-	echo "or     $0 ALIAS" 1>&2
-	echo where ALIAS is a recognized configuration type. 1>&2
-	exit 1
-fi
+me=`echo "$0" | sed -e 's,.*/,,'`
 
-# First pass through any local machine types.
-case $1 in
-	*local*)
-		echo $1
-		exit 0
-		;;
-	*)
-	;;
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+       $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )	# Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help"
+       exit 1 ;;
+
+    *local*)
+       # First pass through any local machine types.
+       echo $1
+       exit ;;
+
+    * )
+       break ;;
+  esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+    exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+    exit 1;;
 esac
 
 # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
 # Here we must recognize all the valid KERNEL-OS combinations.
 maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
 case $maybe_os in
-  linux-gnu*)
+  nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \
+  uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \
+  storm-chaos* | os2-emx* | rtmk-nova*)
     os=-$maybe_os
     basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
     ;;
@@ -94,15 +148,37 @@
 	-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
 	-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
 	-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
-	-apple)
+	-apple | -axis | -knuth | -cray)
 		os=
 		basic_machine=$1
 		;;
+	-sim | -cisco | -oki | -wec | -winbond)
+		os=
+		basic_machine=$1
+		;;
+	-scout)
+		;;
+	-wrs)
+		os=-vxworks
+		basic_machine=$1
+		;;
+	-chorusos*)
+		os=-chorusos
+		basic_machine=$1
+		;;
+ 	-chorusrdb)
+ 		os=-chorusrdb
+		basic_machine=$1
+ 		;;
 	-hiux*)
 		os=-hiuxwe2
 		;;
+	-sco6)
+		os=-sco5v6
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
 	-sco5)
-		os=sco3.2v5
+		os=-sco3.2v5
 		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
 		;;
 	-sco4)
@@ -117,10 +193,17 @@
 		# Don't forget version if it is 3.2v4 or newer.
 		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
 		;;
+	-sco5v6*)
+		# Don't forget version if it is 3.2v4 or newer.
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
 	-sco*)
 		os=-sco3.2v2
 		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
 		;;
+	-udk*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
 	-isc)
 		os=-isc2.2
 		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
@@ -143,26 +226,84 @@
 	-psos*)
 		os=-psos
 		;;
+	-mint | -mint[0-9]*)
+		basic_machine=m68k-atari
+		os=-mint
+		;;
 esac
 
 # Decode aliases for certain CPU-COMPANY combinations.
 case $basic_machine in
 	# Recognize the basic CPU types without company name.
 	# Some are omitted here because they have special meanings below.
-	tahoe | i860 | m32r | m68k | m68000 | m88k | ns32k | arc | arm \
-		| arme[lb] | pyramid | mn10200 | mn10300 | tron | a29k \
-		| 580 | i960 | h8300 | hppa | hppa1.0 | hppa1.1 | hppa2.0 \
-		| alpha | alphaev5 | alphaev56 | we32k | ns16k | clipper \
-		| i370 | sh | powerpc | powerpcle | 1750a | dsp16xx | pdp11 \
-		| mips64 | mipsel | mips64el | mips64orion | mips64orionel \
-		| mipstx39 | mipstx39el \
-		| sparc | sparclet | sparclite | sparc64 | v850)
+	1750a | 580 \
+	| a29k \
+	| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+	| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+	| am33_2.0 \
+	| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \
+	| bfin \
+	| c4x | clipper \
+	| d10v | d30v | dlx | dsp16xx \
+	| fido | fr30 | frv \
+	| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+	| i370 | i860 | i960 | ia64 \
+	| ip2k | iq2000 \
+	| m32c | m32r | m32rle | m68000 | m68k | m88k \
+	| maxq | mb | microblaze | mcore | mep \
+	| mips | mipsbe | mipseb | mipsel | mipsle \
+	| mips16 \
+	| mips64 | mips64el \
+	| mips64vr | mips64vrel \
+	| mips64orion | mips64orionel \
+	| mips64vr4100 | mips64vr4100el \
+	| mips64vr4300 | mips64vr4300el \
+	| mips64vr5000 | mips64vr5000el \
+	| mips64vr5900 | mips64vr5900el \
+	| mipsisa32 | mipsisa32el \
+	| mipsisa32r2 | mipsisa32r2el \
+	| mipsisa64 | mipsisa64el \
+	| mipsisa64r2 | mipsisa64r2el \
+	| mipsisa64sb1 | mipsisa64sb1el \
+	| mipsisa64sr71k | mipsisa64sr71kel \
+	| mipstx39 | mipstx39el \
+	| mn10200 | mn10300 \
+	| mt \
+	| msp430 \
+	| nios | nios2 \
+	| ns16k | ns32k \
+	| or32 \
+	| pdp10 | pdp11 | pj | pjl \
+	| powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+	| pyramid \
+	| score \
+	| sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+	| sh64 | sh64le \
+	| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
+	| sparcv8 | sparcv9 | sparcv9b | sparcv9v \
+	| spu | strongarm \
+	| tahoe | thumb | tic4x | tic80 | tron \
+	| v850 | v850e \
+	| we32k \
+	| x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \
+	| z8k)
+		basic_machine=$basic_machine-unknown
+		;;
+	m6811 | m68hc11 | m6812 | m68hc12)
+		# Motorola 68HC11/12.
 		basic_machine=$basic_machine-unknown
+		os=-none
 		;;
+	m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+		;;
+	ms1)
+		basic_machine=mt-unknown
+		;;
+
 	# We use `pc' rather than `unknown'
 	# because (1) that's what they normally are, and
 	# (2) the word "unknown" tends to confuse beginning users.
-	i[34567]86)
+	i*86 | x86_64)
 	  basic_machine=$basic_machine-pc
 	  ;;
 	# Object if more than one company name word.
@@ -171,27 +312,94 @@
 		exit 1
 		;;
 	# Recognize the basic CPU types with company name.
-	vax-* | tahoe-* | i[34567]86-* | i860-* | m32r-* | m68k-* | m68000-* \
-	      | m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | arm-* | c[123]* \
-	      | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \
-	      | power-* | none-* | 580-* | cray2-* | h8300-* | i960-* \
-	      | xmp-* | ymp-* | hppa-* | hppa1.0-* | hppa1.1-* | hppa2.0-* \
-	      | alpha-* | alphaev5-* | alphaev56-* | we32k-* | cydra-* \
-	      | ns16k-* | pn-* | np1-* | xps100-* | clipper-* | orion-* \
-	      | sparclite-* | pdp11-* | sh-* | powerpc-* | powerpcle-* \
-	      | sparc64-* | mips64-* | mipsel-* \
-	      | mips64el-* | mips64orion-* | mips64orionel-*  \
-	      | mipstx39-* | mipstx39el-* \
-	      | f301-*)
+	580-* \
+	| a29k-* \
+	| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+	| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+	| alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
+	| arm-*  | armbe-* | armle-* | armeb-* | armv*-* \
+	| avr-* | avr32-* \
+	| bfin-* | bs2000-* \
+	| c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
+	| clipper-* | craynv-* | cydra-* \
+	| d10v-* | d30v-* | dlx-* \
+	| elxsi-* \
+	| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
+	| h8300-* | h8500-* \
+	| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+	| i*86-* | i860-* | i960-* | ia64-* \
+	| ip2k-* | iq2000-* \
+	| m32c-* | m32r-* | m32rle-* \
+	| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+	| m88110-* | m88k-* | maxq-* | mcore-* \
+	| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+	| mips16-* \
+	| mips64-* | mips64el-* \
+	| mips64vr-* | mips64vrel-* \
+	| mips64orion-* | mips64orionel-* \
+	| mips64vr4100-* | mips64vr4100el-* \
+	| mips64vr4300-* | mips64vr4300el-* \
+	| mips64vr5000-* | mips64vr5000el-* \
+	| mips64vr5900-* | mips64vr5900el-* \
+	| mipsisa32-* | mipsisa32el-* \
+	| mipsisa32r2-* | mipsisa32r2el-* \
+	| mipsisa64-* | mipsisa64el-* \
+	| mipsisa64r2-* | mipsisa64r2el-* \
+	| mipsisa64sb1-* | mipsisa64sb1el-* \
+	| mipsisa64sr71k-* | mipsisa64sr71kel-* \
+	| mipstx39-* | mipstx39el-* \
+	| mmix-* \
+	| mt-* \
+	| msp430-* \
+	| nios-* | nios2-* \
+	| none-* | np1-* | ns16k-* | ns32k-* \
+	| orion-* \
+	| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+	| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
+	| pyramid-* \
+	| romp-* | rs6000-* \
+	| sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
+	| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+	| sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
+	| sparclite-* \
+	| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \
+	| tahoe-* | thumb-* \
+	| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+	| tron-* \
+	| v850-* | v850e-* | vax-* \
+	| we32k-* \
+	| x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \
+	| xstormy16-* | xtensa*-* \
+	| ymp-* \
+	| z8k-*)
+		;;
+	# Recognize the basic CPU types without company name, with glob match.
+	xtensa*)
+		basic_machine=$basic_machine-unknown
 		;;
 	# Recognize the various machine names and aliases which stand
 	# for a CPU type and a company and sometimes even an OS.
+	386bsd)
+		basic_machine=i386-unknown
+		os=-bsd
+		;;
 	3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
 		basic_machine=m68000-att
 		;;
 	3b*)
 		basic_machine=we32k-att
 		;;
+	a29khif)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+    	abacus)
+		basic_machine=abacus-unknown
+		;;
+	adobe68k)
+		basic_machine=m68010-adobe
+		os=-scout
+		;;
 	alliant | fx80)
 		basic_machine=fx80-alliant
 		;;
@@ -202,25 +410,35 @@
 		basic_machine=a29k-none
 		os=-bsd
 		;;
+	amd64)
+		basic_machine=x86_64-pc
+		;;
+	amd64-*)
+		basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
 	amdahl)
 		basic_machine=580-amdahl
 		os=-sysv
 		;;
 	amiga | amiga-*)
-		basic_machine=m68k-cbm
+		basic_machine=m68k-unknown
 		;;
 	amigaos | amigados)
-		basic_machine=m68k-cbm
+		basic_machine=m68k-unknown
 		os=-amigaos
 		;;
 	amigaunix | amix)
-		basic_machine=m68k-cbm
+		basic_machine=m68k-unknown
 		os=-sysv4
 		;;
 	apollo68)
 		basic_machine=m68k-apollo
 		os=-sysv
 		;;
+	apollo68bsd)
+		basic_machine=m68k-apollo
+		os=-bsd
+		;;
 	aux)
 		basic_machine=m68k-apple
 		os=-aux
@@ -229,6 +447,18 @@
 		basic_machine=ns32k-sequent
 		os=-dynix
 		;;
+	blackfin)
+		basic_machine=bfin-unknown
+		os=-linux
+		;;
+	blackfin-*)
+		basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	c90)
+		basic_machine=c90-cray
+		os=-unicos
+		;;
 	convex-c1)
 		basic_machine=c1-convex
 		os=-bsd
@@ -249,27 +479,45 @@
 		basic_machine=c38-convex
 		os=-bsd
 		;;
-	cray | ymp)
-		basic_machine=ymp-cray
-		os=-unicos
-		;;
-	cray2)
-		basic_machine=cray2-cray
+	cray | j90)
+		basic_machine=j90-cray
 		os=-unicos
 		;;
-	[ctj]90-cray)
-		basic_machine=c90-cray
-		os=-unicos
+	craynv)
+		basic_machine=craynv-cray
+		os=-unicosmp
+		;;
+	cr16)
+		basic_machine=cr16-unknown
+		os=-elf
 		;;
 	crds | unos)
 		basic_machine=m68k-crds
 		;;
+	crisv32 | crisv32-* | etraxfs*)
+		basic_machine=crisv32-axis
+		;;
+	cris | cris-* | etrax*)
+		basic_machine=cris-axis
+		;;
+	crx)
+		basic_machine=crx-unknown
+		os=-elf
+		;;
 	da30 | da30-*)
 		basic_machine=m68k-da30
 		;;
 	decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
 		basic_machine=mips-dec
 		;;
+	decsystem10* | dec10*)
+		basic_machine=pdp10-dec
+		os=-tops10
+		;;
+	decsystem20* | dec20*)
+		basic_machine=pdp10-dec
+		os=-tops20
+		;;
 	delta | 3300 | motorola-3300 | motorola-delta \
 	      | 3300-motorola | delta-motorola)
 		basic_machine=m68k-motorola
@@ -278,6 +526,10 @@
 		basic_machine=m88k-motorola
 		os=-sysv3
 		;;
+	djgpp)
+		basic_machine=i586-pc
+		os=-msdosdjgpp
+		;;
 	dpx20 | dpx20-*)
 		basic_machine=rs6000-bull
 		os=-bosx
@@ -297,6 +549,10 @@
 	encore | umax | mmax)
 		basic_machine=ns32k-encore
 		;;
+	es1800 | OSE68k | ose68k | ose | OSE)
+		basic_machine=m68k-ericsson
+		os=-ose
+		;;
 	fx2800)
 		basic_machine=i860-alliant
 		;;
@@ -307,6 +563,10 @@
 		basic_machine=tron-gmicro
 		os=-sysv
 		;;
+	go32)
+		basic_machine=i386-pc
+		os=-go32
+		;;
 	h3050r* | hiux*)
 		basic_machine=hppa1.1-hitachi
 		os=-hiuxwe2
@@ -315,6 +575,14 @@
 		basic_machine=h8300-hitachi
 		os=-hms
 		;;
+	h8300xray)
+		basic_machine=h8300-hitachi
+		os=-xray
+		;;
+	h8500hms)
+		basic_machine=h8500-hitachi
+		os=-hms
+		;;
 	harris)
 		basic_machine=m88k-harris
 		os=-sysv3
@@ -330,13 +598,30 @@
 		basic_machine=m68k-hp
 		os=-hpux
 		;;
+	hp3k9[0-9][0-9] | hp9[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
 	hp9k2[0-9][0-9] | hp9k31[0-9])
 		basic_machine=m68000-hp
 		;;
 	hp9k3[2-9][0-9])
 		basic_machine=m68k-hp
 		;;
-	hp9k7[0-9][0-9] | hp7[0-9][0-9] | hp9k8[0-9]7 | hp8[0-9]7)
+	hp9k6[0-9][0-9] | hp6[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hp9k7[0-79][0-9] | hp7[0-79][0-9])
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k78[0-9] | hp78[0-9])
+		# FIXME: really hppa2.0-hp
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+		# FIXME: really hppa2.0-hp
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[0-9][13679] | hp8[0-9][13679])
 		basic_machine=hppa1.1-hp
 		;;
 	hp9k8[0-9][0-9] | hp8[0-9][0-9])
@@ -345,27 +630,42 @@
 	hppa-next)
 		os=-nextstep3
 		;;
+	hppaosf)
+		basic_machine=hppa1.1-hp
+		os=-osf
+		;;
+	hppro)
+		basic_machine=hppa1.1-hp
+		os=-proelf
+		;;
 	i370-ibm* | ibm*)
 		basic_machine=i370-ibm
-		os=-mvs
 		;;
 # I'm not sure what "Sysv32" means.  Should this be sysv3.2?
-	i[34567]86v32)
+	i*86v32)
 		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
 		os=-sysv32
 		;;
-	i[34567]86v4*)
+	i*86v4*)
 		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
 		os=-sysv4
 		;;
-	i[34567]86v)
+	i*86v)
 		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
 		os=-sysv
 		;;
-	i[34567]86sol2)
+	i*86sol2)
 		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
 		os=-solaris2
 		;;
+	i386mach)
+		basic_machine=i386-mach
+		os=-mach
+		;;
+	i386-vsta | vsta)
+		basic_machine=i386-unknown
+		os=-vsta
+		;;
 	iris | iris4d)
 		basic_machine=mips-sgi
 		case $os in
@@ -380,6 +680,14 @@
 		basic_machine=m68k-isi
 		os=-sysv
 		;;
+	m68knommu)
+		basic_machine=m68k-unknown
+		os=-linux
+		;;
+	m68knommu-*)
+		basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
 	m88k-omron*)
 		basic_machine=m88k-omron
 		;;
@@ -391,16 +699,20 @@
 		basic_machine=ns32k-utek
 		os=-sysv
 		;;
+	mingw32)
+		basic_machine=i386-pc
+		os=-mingw32
+		;;
+	mingw32ce)
+		basic_machine=arm-unknown
+		os=-mingw32ce
+		;;
 	miniframe)
 		basic_machine=m68000-convergent
 		;;
-	mipsel*-linux*)
-		basic_machine=mipsel-unknown
-		os=-linux-gnu
-		;;
-	mips*-linux*)
-		basic_machine=mips-unknown
-		os=-linux-gnu
+	*mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+		basic_machine=m68k-atari
+		os=-mint
 		;;
 	mips3*-*)
 		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
@@ -408,10 +720,37 @@
 	mips3*)
 		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
 		;;
+	monitor)
+		basic_machine=m68k-rom68k
+		os=-coff
+		;;
+	morphos)
+		basic_machine=powerpc-unknown
+		os=-morphos
+		;;
+	msdos)
+		basic_machine=i386-pc
+		os=-msdos
+		;;
+	ms1-*)
+		basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
+		;;
+	mvs)
+		basic_machine=i370-ibm
+		os=-mvs
+		;;
 	ncr3000)
 		basic_machine=i486-ncr
 		os=-sysv4
 		;;
+	netbsd386)
+		basic_machine=i386-unknown
+		os=-netbsd
+		;;
+	netwinder)
+		basic_machine=armv4l-rebel
+		os=-linux
+		;;
 	news | news700 | news800 | news900)
 		basic_machine=m68k-sony
 		os=-newsos
@@ -424,6 +763,10 @@
 		basic_machine=mips-sony
 		os=-newsos
 		;;
+	necv70)
+		basic_machine=v70-nec
+		os=-sysv
+		;;
 	next | m*-next )
 		basic_machine=m68k-next
 		case $os in
@@ -449,9 +792,39 @@
 		basic_machine=i960-intel
 		os=-nindy
 		;;
+	mon960)
+		basic_machine=i960-intel
+		os=-mon960
+		;;
+	nonstopux)
+		basic_machine=mips-compaq
+		os=-nonstopux
+		;;
 	np1)
 		basic_machine=np1-gould
 		;;
+	nsr-tandem)
+		basic_machine=nsr-tandem
+		;;
+	op50n-* | op60c-*)
+		basic_machine=hppa1.1-oki
+		os=-proelf
+		;;
+	openrisc | openrisc-*)
+		basic_machine=or32-unknown
+		;;
+	os400)
+		basic_machine=powerpc-ibm
+		os=-os400
+		;;
+	OSE68000 | ose68000)
+		basic_machine=m68000-ericsson
+		os=-ose
+		;;
+	os68k)
+		basic_machine=m68k-none
+		os=-os68k
+		;;
 	pa-hitachi)
 		basic_machine=hppa1.1-hitachi
 		os=-hiuxwe2
@@ -460,57 +833,123 @@
 		basic_machine=i860-intel
 		os=-osf
 		;;
+	parisc)
+		basic_machine=hppa-unknown
+		os=-linux
+		;;
+	parisc-*)
+		basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
 	pbd)
 		basic_machine=sparc-tti
 		;;
 	pbb)
 		basic_machine=m68k-tti
 		;;
-        pc532 | pc532-*)
+	pc532 | pc532-*)
 		basic_machine=ns32k-pc532
 		;;
-	pentium | p5 | k5 | nexen)
+	pc98)
+		basic_machine=i386-pc
+		;;
+	pc98-*)
+		basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentium | p5 | k5 | k6 | nexgen | viac3)
 		basic_machine=i586-pc
 		;;
-	pentiumpro | p6 | k6 | 6x86)
+	pentiumpro | p6 | 6x86 | athlon | athlon_*)
 		basic_machine=i686-pc
 		;;
-	pentiumii | pentium2)
+	pentiumii | pentium2 | pentiumiii | pentium3)
+		basic_machine=i686-pc
+		;;
+	pentium4)
 		basic_machine=i786-pc
 		;;
-	pentium-* | p5-* | k5-* | nexen-*)
+	pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
 		basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
 		;;
-	pentiumpro-* | p6-* | k6-* | 6x86-*)
+	pentiumpro-* | p6-* | 6x86-* | athlon-*)
+		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
 		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
 		;;
-	pentiumii-* | pentium2-*)
+	pentium4-*)
 		basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
 		;;
 	pn)
 		basic_machine=pn-gould
 		;;
-	power)	basic_machine=rs6000-ibm
+	power)	basic_machine=power-ibm
 		;;
 	ppc)	basic_machine=powerpc-unknown
-	        ;;
+		;;
 	ppc-*)	basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
 		;;
 	ppcle | powerpclittle | ppc-le | powerpc-little)
 		basic_machine=powerpcle-unknown
-	        ;;
+		;;
 	ppcle-* | powerpclittle-*)
 		basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
 		;;
+	ppc64)	basic_machine=powerpc64-unknown
+		;;
+	ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+		basic_machine=powerpc64le-unknown
+		;;
+	ppc64le-* | powerpc64little-*)
+		basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
 	ps2)
 		basic_machine=i386-ibm
 		;;
+	pw32)
+		basic_machine=i586-unknown
+		os=-pw32
+		;;
+	rdos)
+		basic_machine=i386-pc
+		os=-rdos
+		;;
+	rom68k)
+		basic_machine=m68k-rom68k
+		os=-coff
+		;;
 	rm[46]00)
 		basic_machine=mips-siemens
 		;;
 	rtpc | rtpc-*)
 		basic_machine=romp-ibm
 		;;
+	s390 | s390-*)
+		basic_machine=s390-ibm
+		;;
+	s390x | s390x-*)
+		basic_machine=s390x-ibm
+		;;
+	sa29200)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	sb1)
+		basic_machine=mipsisa64sb1-unknown
+		;;
+	sb1el)
+		basic_machine=mipsisa64sb1el-unknown
+		;;
+	sde)
+		basic_machine=mipsisa32-sde
+		os=-elf
+		;;
+	sei)
+		basic_machine=mips-sei
+		os=-seiux
+		;;
 	sequent)
 		basic_machine=i386-sequent
 		;;
@@ -518,6 +957,16 @@
 		basic_machine=sh-hitachi
 		os=-hms
 		;;
+	sh5el)
+		basic_machine=sh5le-unknown
+		;;
+	sh64)
+		basic_machine=sh64-unknown
+		;;
+	sparclite-wrs | simso-wrs)
+		basic_machine=sparclite-wrs
+		os=-vxworks
+		;;
 	sps7)
 		basic_machine=m68k-bull
 		os=-sysv2
@@ -525,6 +974,13 @@
 	spur)
 		basic_machine=spur-unknown
 		;;
+	st2000)
+		basic_machine=m68k-tandem
+		;;
+	stratus)
+		basic_machine=i860-stratus
+		os=-sysv4
+		;;
 	sun2)
 		basic_machine=m68000-sun
 		;;
@@ -565,19 +1021,55 @@
 	sun386 | sun386i | roadrunner)
 		basic_machine=i386-sun
 		;;
+	sv1)
+		basic_machine=sv1-cray
+		os=-unicos
+		;;
 	symmetry)
 		basic_machine=i386-sequent
 		os=-dynix
 		;;
+	t3e)
+		basic_machine=alphaev5-cray
+		os=-unicos
+		;;
+	t90)
+		basic_machine=t90-cray
+		os=-unicos
+		;;
+	tic54x | c54x*)
+		basic_machine=tic54x-unknown
+		os=-coff
+		;;
+	tic55x | c55x*)
+		basic_machine=tic55x-unknown
+		os=-coff
+		;;
+	tic6x | c6x*)
+		basic_machine=tic6x-unknown
+		os=-coff
+		;;
+	tile*)
+		basic_machine=tile-unknown
+		os=-linux-gnu
+		;;
 	tx39)
 		basic_machine=mipstx39-unknown
 		;;
 	tx39el)
 		basic_machine=mipstx39el-unknown
 		;;
+	toad1)
+		basic_machine=pdp10-xkl
+		os=-tops20
+		;;
 	tower | tower-32)
 		basic_machine=m68k-ncr
 		;;
+	tpf)
+		basic_machine=s390x-ibm
+		os=-tpf
+		;;
 	udi29k)
 		basic_machine=a29k-amd
 		os=-udi
@@ -586,6 +1078,10 @@
 		basic_machine=a29k-nyu
 		os=-sym1
 		;;
+	v810 | necv810)
+		basic_machine=v810-nec
+		os=-none
+		;;
 	vaxv)
 		basic_machine=vax-dec
 		os=-sysv
@@ -595,8 +1091,8 @@
 		os=-vms
 		;;
 	vpp*|vx|vx-*)
-               basic_machine=f301-fujitsu
-               ;;
+		basic_machine=f301-fujitsu
+		;;
 	vxworks960)
 		basic_machine=i960-wrs
 		os=-vxworks
@@ -609,13 +1105,29 @@
 		basic_machine=a29k-wrs
 		os=-vxworks
 		;;
-	xmp)
-		basic_machine=xmp-cray
-		os=-unicos
+	w65*)
+		basic_machine=w65-wdc
+		os=-none
+		;;
+	w89k-*)
+		basic_machine=hppa1.1-winbond
+		os=-proelf
 		;;
-        xps | xps100)
+	xbox)
+		basic_machine=i686-pc
+		os=-mingw32
+		;;
+	xps | xps100)
 		basic_machine=xps100-honeywell
 		;;
+	ymp)
+		basic_machine=ymp-cray
+		os=-unicos
+		;;
+	z8k-*-coff)
+		basic_machine=z8k-unknown
+		os=-sim
+		;;
 	none)
 		basic_machine=none-none
 		os=-none
@@ -623,32 +1135,44 @@
 
 # Here we handle the default manufacturer of certain CPU types.  It is in
 # some cases the only manufacturer, in others, it is the most popular.
-	mips)
-		if [ x$os = x-linux-gnu ]; then
-			basic_machine=mips-unknown
-		else
-			basic_machine=mips-mips
-		fi
+	w89k)
+		basic_machine=hppa1.1-winbond
+		;;
+	op50n)
+		basic_machine=hppa1.1-oki
+		;;
+	op60c)
+		basic_machine=hppa1.1-oki
 		;;
 	romp)
 		basic_machine=romp-ibm
 		;;
+	mmix)
+		basic_machine=mmix-knuth
+		;;
 	rs6000)
 		basic_machine=rs6000-ibm
 		;;
 	vax)
 		basic_machine=vax-dec
 		;;
+	pdp10)
+		# there are many clones, so DEC is not a safe bet
+		basic_machine=pdp10-unknown
+		;;
 	pdp11)
 		basic_machine=pdp11-dec
 		;;
 	we32k)
 		basic_machine=we32k-att
 		;;
-	sparc)
+	sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele)
+		basic_machine=sh-unknown
+		;;
+	sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
 		basic_machine=sparc-sun
 		;;
-        cydra)
+	cydra)
 		basic_machine=cydra-cydrome
 		;;
 	orion)
@@ -657,6 +1181,15 @@
 	orion105)
 		basic_machine=clipper-highlevel
 		;;
+	mac | mpw | mac-mpw)
+		basic_machine=m68k-apple
+		;;
+	pmac | pmac-mpw)
+		basic_machine=powerpc-apple
+		;;
+	*-unknown)
+		# Make sure to match an already-canonicalized machine name.
+		;;
 	*)
 		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
 		exit 1
@@ -709,14 +1242,49 @@
 	      | -aos* \
 	      | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
 	      | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
-	      | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \
-	      | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* \
+	      | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
+	      | -openbsd* | -solidbsd* \
+	      | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+	      | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
 	      | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
 	      | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+	      | -chorusos* | -chorusrdb* \
 	      | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
-	      | -mingw32* | -linux-gnu* | -uxpv* | -beos*)
+	      | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \
+	      | -uxpv* | -beos* | -mpeix* | -udk* \
+	      | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+	      | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+	      | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+	      | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+	      | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+	      | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+	      | -skyos* | -haiku* | -rdos* | -toppers* | -drops*)
 	# Remember, each alternative MUST END IN *, to match a version number.
 		;;
+	-qnx*)
+		case $basic_machine in
+		    x86-* | i*86-*)
+			;;
+		    *)
+			os=-nto$os
+			;;
+		esac
+		;;
+	-nto-qnx*)
+		;;
+	-nto*)
+		os=`echo $os | sed -e 's|nto|nto-qnx|'`
+		;;
+	-sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+	      | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
+	      | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+		;;
+	-mac*)
+		os=`echo $os | sed -e 's|mac|macos|'`
+		;;
+	-linux-dietlibc)
+		os=-linux-dietlibc
+		;;
 	-linux*)
 		os=`echo $os | sed -e 's|linux|linux-gnu|'`
 		;;
@@ -726,6 +1294,15 @@
 	-sunos6*)
 		os=`echo $os | sed -e 's|sunos6|solaris3|'`
 		;;
+	-opened*)
+		os=-openedition
+		;;
+        -os400*)
+		os=-os400
+		;;
+	-wince*)
+		os=-wince
+		;;
 	-osfrose*)
 		os=-osfrose
 		;;
@@ -741,11 +1318,26 @@
 	-acis*)
 		os=-aos
 		;;
+	-atheos*)
+		os=-atheos
+		;;
+	-syllable*)
+		os=-syllable
+		;;
+	-386bsd)
+		os=-bsd
+		;;
 	-ctix* | -uts*)
 		os=-sysv
 		;;
+	-nova*)
+		os=-rtmk-nova
+		;;
 	-ns2 )
-	        os=-nextstep2
+		os=-nextstep2
+		;;
+	-nsk*)
+		os=-nsk
 		;;
 	# Preserve the version number of sinix5.
 	-sinix5.*)
@@ -754,6 +1346,9 @@
 	-sinix*)
 		os=-sysv4
 		;;
+        -tpf*)
+		os=-tpf
+		;;
 	-triton*)
 		os=-sysv3
 		;;
@@ -772,9 +1367,27 @@
 	# This must come after -sysvr4.
 	-sysv*)
 		;;
+	-ose*)
+		os=-ose
+		;;
+	-es1800*)
+		os=-ose
+		;;
 	-xenix)
 		os=-xenix
 		;;
+	-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+		os=-mint
+		;;
+	-aros*)
+		os=-aros
+		;;
+	-kaos*)
+		os=-kaos
+		;;
+	-zvmoe)
+		os=-zvmoe
+		;;
 	-none)
 		;;
 	*)
@@ -797,13 +1410,29 @@
 # system, and we'll never get to this point.
 
 case $basic_machine in
+        score-*)
+		os=-elf
+		;;
+        spu-*)
+		os=-elf
+		;;
 	*-acorn)
 		os=-riscix1.2
 		;;
+	arm*-rebel)
+		os=-linux
+		;;
 	arm*-semi)
 		os=-aout
 		;;
-        pdp11-*)
+        c4x-* | tic4x-*)
+        	os=-coff
+		;;
+	# This must come before the *-dec entry.
+	pdp10-*)
+		os=-tops20
+		;;
+	pdp11-*)
 		os=-none
 		;;
 	*-dec | vax-*)
@@ -821,6 +1450,21 @@
 		# default.
 		# os=-sunos4
 		;;
+	m68*-cisco)
+		os=-aout
+		;;
+        mep-*)
+		os=-elf
+		;;
+	mips*-cisco)
+		os=-elf
+		;;
+	mips*-*)
+		os=-elf
+		;;
+	or32-*)
+		os=-coff
+		;;
 	*-tti)	# must be before sparc entry or we get the wrong os.
 		os=-sysv3
 		;;
@@ -830,9 +1474,24 @@
 	*-be)
 		os=-beos
 		;;
+	*-haiku)
+		os=-haiku
+		;;
 	*-ibm)
 		os=-aix
 		;;
+    	*-knuth)
+		os=-mmixware
+		;;
+	*-wec)
+		os=-proelf
+		;;
+	*-winbond)
+		os=-proelf
+		;;
+	*-oki)
+		os=-proelf
+		;;
 	*-hp)
 		os=-hpux
 		;;
@@ -875,27 +1534,39 @@
 	*-next)
 		os=-nextstep3
 		;;
-        *-gould)
+	*-gould)
 		os=-sysv
 		;;
-        *-highlevel)
+	*-highlevel)
 		os=-bsd
 		;;
 	*-encore)
 		os=-bsd
 		;;
-        *-sgi)
+	*-sgi)
 		os=-irix
 		;;
-        *-siemens)
+	*-siemens)
 		os=-sysv4
 		;;
 	*-masscomp)
 		os=-rtu
 		;;
-	f301-fujitsu)
+	f30[01]-fujitsu | f700-fujitsu)
 		os=-uxpv
 		;;
+	*-rom68k)
+		os=-coff
+		;;
+	*-*bug)
+		os=-coff
+		;;
+	*-apple)
+		os=-macos
+		;;
+	*-atari*)
+		os=-mint
+		;;
 	*)
 		os=-none
 		;;
@@ -917,9 +1588,15 @@
 			-aix*)
 				vendor=ibm
 				;;
+			-beos*)
+				vendor=be
+				;;
 			-hpux*)
 				vendor=hp
 				;;
+			-mpeix*)
+				vendor=hp
+				;;
 			-hiux*)
 				vendor=hitachi
 				;;
@@ -935,21 +1612,47 @@
 			-genix*)
 				vendor=ns
 				;;
-			-mvs*)
+			-mvs* | -opened*)
+				vendor=ibm
+				;;
+			-os400*)
 				vendor=ibm
 				;;
 			-ptx*)
 				vendor=sequent
 				;;
-			-vxsim* | -vxworks*)
+			-tpf*)
+				vendor=ibm
+				;;
+			-vxsim* | -vxworks* | -windiss*)
 				vendor=wrs
 				;;
 			-aux*)
 				vendor=apple
 				;;
+			-hms*)
+				vendor=hitachi
+				;;
+			-mpw* | -macos*)
+				vendor=apple
+				;;
+			-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+				vendor=atari
+				;;
+			-vos*)
+				vendor=stratus
+				;;
 		esac
 		basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
 		;;
 esac
 
 echo $basic_machine$os
+exit
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
--- debathena-moira-4.0.0+cvs20080304.orig/afssync/INSTRUCTIONS
+++ debathena-moira-4.0.0+cvs20080304/afssync/INSTRUCTIONS
@@ -0,0 +1,196 @@
+The executables are in /moira/bin/ on the moira server, with sources
+in /mit/moiradev/src/afssync/.  Most of the commands are run on the
+Moira server.
+
+####	Set up a workspace						####
+
+mkdir -p /moira/sync
+cd /moira/sync
+
+####	This is preparation for the resync, to save non-Moira users.    ####
+First, get a recent copy of the prdb, and extract non-Moira entries:
+
+	/moira/bin/udebug prill -port 7002
+	rcp -px root@prill:/usr/afs/db/prdb.DB0 prdb.old
+	/moira/bin/udebug prill -port 7002
+If the two udebugs show that the version changed, lather-rinse-repeat.
+(udebug can be found in /usr/athena/bin; "prill" here and below is some 
+DB server)
+(Also check for "0 of them for write" at the end.  It might matter.)
+
+	/moira/bin/pt_util -x -m -u -g -d prdb.extra -p prdb.old
+	perl /moira/bin/pt_util.pl < prdb.extra > prdb.extra.sort
+to extract and prepare the personal groups and special user entries in
+the old prdb for being reincorporated into the new prdb.
+
+	awk -F\| '$9 == 3 {print $1}' /backup/backup_1/users > /tmp/deactivated
+
+and the following perl script:
+
+#!/usr/athena/bin/perl -w
+
+open(OUT, ">prdb.extra.trimmed");
+
+for ( `cat /tmp/deactivated` ) {
+    chop;
+    $ex{$_} = 1;
+}
+
+$punt = 0;
+
+foreach $L ( `cat prdb.extra.sort` ) {
+    @w = split(/ /,$L);
+    $_ = $w[0];
+    if ( /:/ ) {
+        @x = split(/:/,$w[0]);
+        if ($ex{$x[0]}) {
+            $punt=1;
+        } else {
+            $punt=0;
+        }
+    } else {
+	# If we got here, we're either a user, a prefixless
+	# group, or a group member.
+	$punt = 0 if $w[0];
+    }
+    print OUT $L unless $punt == 1;
+}
+
+close(OUT);
+exit 0;
+
+to remove the personal groups for users who are deactivated
+
+	awk '/^[^ ][^:]*@/ {printf "KERBEROS:%s\n",$1}' prdb.extra.trimmed \
+		> foreign
+	blanche afs-foreign-users -f foreign
+Get a list of all the @andrew.cmu.edu type (non- athena.mit.edu cell)
+users, and sync the Moira list afs-foreign-users to this list.
+Moira then adds those entries to the group system:afs-foreign-users,
+thus keeping them from being lost in the prdb resync.
+Sanity checking the diffs before running the blanche command is recommended.
+
+	awk '/^[^ 0-9][^:@]*$/ {printf "KERBEROS:%s@ATHENA.MIT.EDU\n",$1}' \
+		prdb.extra.trimmed > oddities
+	awk '/^[^ ][0-9.]* .*$/ {printf "KERBEROS:%s\n",$1}' prdb.extra.trimmed\
+		 >> oddities
+	echo "LIST:afs-foreign-users" >> oddities
+	blanche afs-odd-entities -f oddities
+Do the equivalent of afs-foreign-users for domestic users.  We make
+the afs-foreign-users list a member of the more general afs-odd-entities.
+Sanity checking the diffs before running the blanche command is recommended.
+
+WAIT for the incremental updates from the `blanche` changes to complete.
+
+####   Now the actual resync begins.  Incremental updates must stop.   ####
+
+	touch /moira/afs/noafs
+to disable AFS incremental updates during the synchronization.  The
+afs.incr (?) will wait 30 minutes on an incremental update before
+timing out, so the resync should complete in that time, or list
+changes in Moira might need to be propagated by hand.
+
+	/moira/bin/afssync prdb.moira
+to dump the prdb data that is in Moira (users, groups, and group
+memberships).  This step takes about ten minutes, but can be done
+concurrently with the next few steps.
+
+REPEAT the above commands, thus regenerating prdb.trimmed from a now
+completely-up-to-date prdb.
+
+*** Make sure the "afssync" command has completed ***
+
+	cp prdb.moira prdb.new
+	/moira/bin/pt_util -w -d prdb.extra.trimmed -p prdb.new \
+		>& prdb.extra.err
+This use of pt_util will presumably log errors about failed user
+creations and list additions.  (To start over, do both the `cp` and
+`pt_util` again.)  You can filter out the "User or group doesn't exist"
+type of lines that were caused by a user deactivation with something
+like:
+	awk -F\| '$9 == 3 {print $1}' /backup/backup_1/users > /tmp/deactivated
+	perl -e 'for(`cat /tmp/deactivated`){ chop; $ex{$_}=1;} \
+		foreach $L (`cat prdb.extra.err`){ $f=0; \
+		@w=split(/[ :]/,$L); for(@w){ $f=1 if $ex{$_}; } \
+		next if $f; print $L; }'
+Now, back to the resync.
+
+The only remaining errors should be errors creating system:foo groups,
+be cause they already exist.  These generally mean that that group has
+an odd user on it (root instance, IP acl, etc.) and can safely be
+ignored.
+
+Errors of the form:
+Error while creating dcctdw:foo: Badly formed name (group prefix doesn't match owner?)
+are probably an indication that a user with personal groups had a
+username change (in the past they have also meant that a user with
+personal groups was deactivated and the uid was re-used (this was
+becasue we didn't trim the prdb.extra.sort file in the past.))
+Assuming htese errors are due to a username change, the groups should
+be renamed, and you should regenerate prdb.extra.trimmed starting with
+a fresh prdb from prill.  (You may want to abort and
+rm /moira/afs/noafs and try again later.)
+
+	pts listmax > prdb.listmax
+	foreach i ( <db servers> )
+	    rsh $i -l root -x /bin/athena/detach -a 	# detach packs
+	    rsh $i -l root -x rm -f /usr/afs/db/{prdb.new,pre-resync-prdb}
+	    rcp -px prdb.new root@${i}:/usr/afs/db/prdb.new
+	end						# staging
+	foreach i ( <db servers> )
+	    bos shutdown $i ptserver -wait
+	    bos exec $i "mv /usr/afs/db/prdb.DB0 /usr/afs/db/pre-resync-prdb; rm /usr/afs/db/prdb.DB*; mv /usr/afs/db/prdb.new /usr/afs/db/prdb.DB0"
+	end
+	foreach i ( <db servers> )
+	    bos restart $i ptserver
+	end
+
+	/moira/bin/udebug prill -port 7002
+to watch the status of the servers to make sure things are going well,
+where "prill" is preferred db server (the sync site).
+
+Make sure the beacons are working, and that once quorum is established
+(~90 seconds) that the servers are resynchronizing their notions of
+the databases and that the "dbcurrent" and "up" fields all become set
+and the state goes to "1f".  Also, if "sdi" isn't running, watch out
+for large rx packet queues on port 7002 using rxdebug, as the
+fileservers may get excessively backlogged, and restart servers, if
+necessary, if the congestion remains excessive.
+
+	pts listmax
+	cat prdb.listmax
+and if the id maxima are lower than the saved ones, reset them
+appropriately to the saved ones using `pts setmax`.
+
+	pts ex system:administrators
+as a good spot check, especially since it has special people.
+(also spot check one of the personal groups and perhaps, something like
+the membership of rcmd.reynelda)
+
+	rm /moira/afs/noafs
+to remove the lock file and let Moira's afs incrementals continue.
+
+	The afssync program doesn't deal with null instance KERBEROS
+members of lists which are groups (example: if LIST zacheiss contains
+KERBEROS zacheiss@ATHENA.MIT.EDU).  To get around this, run:
+
+/moira/bin/sync.pl
+
+Which will create /var/tmp/sync.out, which contains the pts commands
+needed to add all the null instance KERBEROS members back to the pts
+groups they belong in.  If it looks sane, run:
+
+sh /var/tmp/sync.out
+
+Any failed additions are probably from lists that contain both USER
+username and KERBEROS username@ATHENA.MIT.EDU.
+
+NOTES
+
+1. Don't do this when you're tired...  There may be no cleanup procedure
+available, with certain mistakes.
+
+2. /moira/afs/noafs is only good for 30 minutes.  Keep track of the
+critical log, and you may have to do some operations by hand when the
+operation is complete.  Also, if requests depend on other requests, they
+may be processed out of order, and fail, and may need to be done by hand.
--- debathena-moira-4.0.0+cvs20080304.orig/afssync/Makefile.in
+++ debathena-moira-4.0.0+cvs20080304/afssync/Makefile.in
@@ -0,0 +1,67 @@
+# $Id: Makefile.in,v 1.8 2002-09-25 20:46:51 zacheiss Exp $
+
+SHELL=/bin/sh
+@SET_MAKE@
+
+CC=@CC@
+CPPFLAGS=@CPPFLAGS@
+AFS_CPPFLAGS=@AFS_CPPFLAGS@
+CFLAGS=@CFLAGS@
+DEFS=@DEFS@
+ALL_CFLAGS=$(CPPFLAGS) $(AFS_CPPFLAGS) $(CFLAGS) $(DEFS)
+PRO_C=@PRO_C@
+PRO_C_DEFS=@PRO_C_DEFS@
+PRO_C_INCLUDES=@PRO_C_INCLUDES@
+AFS_PRO_C_INCLUDES=@AFS_PRO_C_INCLUDES@
+PRO_C_OPTS=@PRO_C_OPTS@
+PRO_C_FLAGS=$(PRO_C_OPTS) $(PRO_C_DEFS) $(PRO_C_INCLUDES) $(AFS_PRO_C_INCLUDES)
+LDFLAGS=@LDFLAGS@
+AFS_LIBS=@AFS_LIBS@
+AFS_DIR=@AFS_DIR@
+SQL_LIBS=@SQL_LIBS@
+LIBS=@LIBS@
+MR_LIBDEP=@MR_LIBDEP@
+INSTALL=@INSTALL@
+INSTALL_PROGRAM=@INSTALL_PROGRAM@
+
+srcdir=@srcdir@
+VPATH=@srcdir@
+SRCTOP=@top_srcdir@
+BUILDTOP=..
+mrbindir=@mrbindir@
+
+SYNC_OBJS=sync.o ptutils.o utils.o ubik.o
+UTIL_OBJS=pt_util.o ptutils.o utils.o ubik.o vis.o
+
+CFILES=sync.c
+
+TARGET=afssync pt_util
+
+.SUFFIXES: .pc
+
+.pc.c:
+	$(PRO_C) $(PRO_C_FLAGS) INAME=$< ONAME=$@
+
+.c.o:
+	$(CC) -c $(ALL_CFLAGS) $<
+
+all: $(TARGET)
+
+clean:
+	rm -f $(SYNC_OBJS) $(UTIL_OBJS) $(CFILES) $(TARGET)
+
+cleandir distclean: clean
+	rm -f Makefile
+
+depend: $(CFILES)
+
+install:
+	$(INSTALL_PROGRAM) afssync $(mrbindir)
+	$(INSTALL_PROGRAM) pt_util $(mrbindir)
+	$(INSTALL_PROGRAM) $(srcdir)/pt_util.pl $(mrbindir)
+
+afssync: $(SYNC_OBJS) $(MR_LIBDEP)
+	$(CC) -o $@ $(LDFLAGS) $(SYNC_OBJS) $(AFS_LIBS) -llwp -lprot $(SQL_LIBS) $(LIBS)
+
+pt_util: $(UTIL_OBJS) $(MR_LIBDEP)
+	$(CC) -o $@ $(LDFLAGS) $(UTIL_OBJS) $(AFS_LIBS) -llwp -lprot $(LIBS)
--- debathena-moira-4.0.0+cvs20080304.orig/afssync/pt_util-fast.c
+++ debathena-moira-4.0.0+cvs20080304/afssync/pt_util-fast.c
@@ -0,0 +1,551 @@
+/*
+ *
+ * ptdump: Program to dump the AFS protection server database
+ *         into an ascii file.
+ *
+ *	Assumptions: We *cheat* here and read the datafile directly, ie.
+ *	             not going through the ubik distributed data manager.
+ *		     therefore the database must be quiescent for the
+ *		     output of this program to be valid.
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <sys/file.h>
+
+#include <afs/param.h>
+#include <lock.h>
+#include <netinet/in.h>
+#define UBIK_INTERNALS
+#include <ubik.h>
+#include <rx/xdr.h>
+#include <rx/rx.h>
+#include "ptint.h"
+#include "ptserver.h"
+#include "pterror.h"
+
+#define IDHash(x) (abs(x) % HASHSIZE)
+#define print_id(x) ( ((flags&DO_SYS)==0 && (x<-32767 || x>97536)) || \
+		      ((flags&DO_OTR)==0 && (x>-32768 && x<97537)))
+
+extern char *optarg;
+extern int optind;
+extern int errno;
+extern char *sys_errlist[];
+#define strerror(a) sys_errlist[a]
+
+int display_entry();
+void add_group();
+void display_groups();
+void display_group();
+void fix_pre();
+char *checkin();
+char *check_core();
+char *id_to_name();
+
+struct hash_entry {
+    char h_name[PR_MAXNAMELEN];
+    int h_id;
+    struct hash_entry *next;
+};
+struct hash_entry *hat[HASHSIZE];
+
+static struct contentry prco;
+static struct prentry pre;
+static struct prheader prh;
+static struct ubik_version uv;
+
+struct grp_list {
+    struct grp_list	*next;
+    long		groups[1024];
+};
+static struct grp_list *grp_head=0;
+static long grp_count=0;
+
+struct usr_list {
+    struct usr_list *next;
+    char name[PR_MAXNAMELEN];
+    long uid;
+};
+static struct usr_list *usr_head=0;
+
+char buffer[1024];
+int dbase_fd;
+FILE *dfp;
+
+#define FMT_BASE "%-10s %d/%d %d %d %d\n"
+#define FMT_MEM  "   %-8s %d\n"
+
+#define DO_USR 1
+#define DO_GRP 2
+#define DO_MEM 4
+#define DO_SYS 8
+#define DO_OTR 16
+
+int nflag = 0;
+int wflag = 0;
+int flags = 0;
+
+main(argc, argv)
+int argc;
+char **argv;
+{
+    register int i;
+    register long code;
+    long cc, upos, gpos;
+    struct prentry uentry, gentry;
+    struct ubik_hdr *uh;
+    char *dfile = 0;
+    char *pfile = "/usr/afs/db/prdb.DB0";
+    int need_gwrite = 0;
+    
+    while ((cc = getopt(argc, argv, "wugmxsnp:d:")) != EOF) {
+	switch (cc) {
+	case 'p':
+	    pfile = optarg;
+	    break;
+	case 'd':
+	    dfile = optarg;
+	    break;
+	case 'n':
+	    nflag++;
+	    break;
+	case 'w':
+	    wflag++;
+	    break;
+	case 'u':
+	    flags |= DO_USR;
+	    break;
+	case 'm':
+	    flags |= (DO_GRP|DO_MEM);
+	    break;
+	case 'g':
+	    flags |= DO_GRP;
+	    break;
+	case 's':
+	    flags |= DO_SYS;
+	    break;
+	case 'x':
+	    flags |= DO_OTR;
+	    break;
+	default:
+	    fprintf(stderr,
+		    "Usage: ptdump [options] [-d data] [-p prdb]\n");
+	    fputs("  Options:\n", stderr);
+	    fputs("    -w  Update prdb with contents of data file\n", stderr);
+	    fputs("    -u  Display users\n", stderr);
+	    fputs("    -g  Display groups\n", stderr);
+	    fputs("    -m  Display group members\n", stderr);
+	    fputs("    -n  Follow name hash chains (not id hashes)\n", stderr);
+	    fputs("    -s  Display only system (Moira) data\n", stderr);
+	    fputs("    -x  Display extra users/groups\n", stderr);
+	    exit(1);
+	}
+    }
+    if ((dbase_fd = open(pfile, wflag ? O_RDWR : O_RDONLY, 0600)) < 0) {
+	fprintf(stderr, "ptdump: cannot open %s: %s\n",
+		pfile, sys_errlist[errno]);
+	exit (1);
+    }
+    if (read(dbase_fd, buffer, HDRSIZE) < 0) {
+	fprintf(stderr, "ptdump: error reading %s: %s\n",
+		pfile, sys_errlist[errno]);
+	exit (1);
+    }
+
+    if (dfile) {
+	if ((dfp = fopen(dfile, wflag ? "r" : "w")) == 0) {
+	    fprintf(stderr, "ptdump: error opening %s: %s\n",
+		    dfile, sys_errlist[errno]);
+	    exit(1);
+	}
+    } else
+	dfp = (wflag ? stdin : stdout);
+
+    uh = (struct ubik_hdr *)buffer;
+    if (ntohl(uh->magic) != UBIK_MAGIC)
+	fprintf(stderr, "ptdump: %s: Bad UBIK_MAGIC. Is %x should be %x\n",
+		pfile, ntohl(uh->magic), UBIK_MAGIC);
+    memcpy(&uv, &uh->version, sizeof(struct ubik_version));
+    fprintf(stderr, "Ubik Version is: %d.%d\n",
+	    ntohl(uv.epoch), ntohl(uv.counter));
+    if (read(dbase_fd, &prh, sizeof(struct prheader)) < 0) {
+	fprintf(stderr, "ptdump: error reading %s: %s\n",
+		pfile, sys_errlist[errno]);
+	exit (1);
+    }
+
+    Initdb();
+    initialize_pt_error_table();
+
+#define FLUSH_GROUP \
+    if (need_gwrite) { \
+	code = pr_WriteEntry(0,0,gpos,&gentry); \
+	if (code) \
+	    fprintf(stderr, "Error while writing group %s: %s\n", \
+		    gentry.name, error_message(code)); \
+	else need_write = 0; \
+    }
+
+    if (wflag) {
+	struct usr_list *u;
+
+	while(fgets(buffer, sizeof(buffer), dfp)) {
+	    int id, oid, cid, flags, quota, uid;
+	    char name[PR_MAXNAMELEN], mem[PR_MAXNAMELEN];
+
+	    if (isspace(*buffer)) {
+		sscanf(buffer, "%s %d", mem, &uid);
+
+		for (u=usr_head; u; u=u->next)
+		    if (u->uid && u->uid==uid) break;
+		if (u) {
+		    /* Add user - deferred because it is probably foreign */
+		    u->uid = 0;
+		    if (upos = FindByID(0, uid))
+			code = PRIDEXIST;
+		    else {
+			if (!code && (flags&(PRGRP|PRQUOTA))==(PRGRP|PRQUOTA)){
+			    gentry.ngroups++;
+			    code = pr_WriteEntry(0,0,gpos,&gentry);
+			    if (code)
+				fprintf(stderr, "Error setting group count on %s: %s\n",
+					name, error_message(code));
+			}
+			code = CreateEntry
+			    (0, u->name, &uid, 1/*idflag*/, 1/*gflag*/,
+			     SYSADMINID/*oid*/, SYSADMINID/*cid*/);
+		    }
+		    if (code)
+			fprintf(stderr, "Error while creating %s: %s\n",
+				u->name, error_message(code));
+		    continue;
+		}
+		/* Add user to group */
+		if (id==ANYUSERID || id==AUTHUSERID || uid==ANONYMOUSID) {
+		    code = PRPERM;
+		}
+		if (!code && !upos) {
+		    upos = FindByID(0,uid);
+		    if (upos) code = pr_ReadEntry(0,0,upos,&uentry);
+		}
+		if (!upos || !gpos)
+		    code = PRNOENT;
+
+		/* Fast group update */
+		if (!code && (gentry.count < PRSIZE)) {
+		    gentry.count++;
+		    for (i=0; i<PRSIZE; i++) {
+			if (gentry.entries[i] == PRBADID) {
+			    gentry.entries[i] = uid;
+			    break;
+			}
+		    }
+		} else {
+		    FLUSH_GROUP;
+		    if (!code) code = AddToEntry (0, &gentry, gpos, uid);
+		}
+		
+		if (!code) code = AddToEntry (0, &uentry, upos, id);
+
+		if (code)
+		    fprintf(stderr, "Error while adding %s to %s: %s\n",
+			    mem, name, error_message(code));
+	    } else {
+		FLUSH_GROUP;
+		sscanf(buffer, "%s %d/%d %d %d %d",
+		       name, &flags, &quota, &id, &oid, &cid);
+
+		if (gpos = FindByID(0, id))
+		    code = PRIDEXIST;
+		else {
+		    code = CreateEntry(0, name, &id, 1/*idflag*/,
+				       flags&PRGRP, oid, cid);
+		    if (!code) gpos = FindByID(0, id);
+		}
+		if (code == PRBADNAM) {
+		    u = (struct usr_list *)malloc(sizeof(struct usr_list));
+		    u->next = usr_head;
+		    u->uid = id;
+		    strcpy(u->name, name);
+		    usr_head = u;
+		} else
+		if (code) {
+		    fprintf(stderr, "Error while creating %s: %s\n",
+			    name, error_message(code));
+		}
+		code = pr_ReadEntry(0,0,gpos,&gentry);
+		if (code)
+		    fprintf(stderr,"Error while reading group %s: %s\n",
+			    name, error_message(code));
+		else if ((flags&PRACCESS) ||
+			 (flags&(PRGRP|PRQUOTA))==(PRGRP|PRQUOTA)) {
+		    gentry.flags = flags;
+		    gentry.ngroups = quota;
+		    need_gwrite = 1;
+		    if (code)
+			fprintf(stderr,
+				"Error while setting flags on %s: %s\n",
+				name, error_message(code));
+		}
+	    }
+	}
+	FLUSH_GROUP;
+	for (u=usr_head; u; u=u->next)
+	    if (u->uid)
+		fprintf(stderr, "Error while creating %s: %s\n",
+			u->name, error_message(PRBADNAM));
+    } else {
+	for (i = 0; i < HASHSIZE; i++) {
+	    upos = nflag ? ntohl(prh.nameHash[i]) : ntohl(prh.idHash[i]);
+	    while (upos)
+		upos = display_entry(upos);
+	}
+	if (flags & DO_GRP)
+	    display_groups();
+    }
+
+    lseek (dbase_fd, 0, L_SET);		/* rewind to beginning of file */
+    if (read(dbase_fd, buffer, HDRSIZE) < 0) {
+	fprintf(stderr, "ptdump: error reading %s: %s\n",
+		pfile, sys_errlist[errno]);
+	exit (1);
+    }
+    uh = (struct ubik_hdr *)buffer;
+    if ((uh->version.epoch != uv.epoch) ||
+	(uh->version.counter != uv.counter)) {
+	fprintf(stderr, "ptdump: Ubik Version number changed during execution.\n");
+	fprintf(stderr, "Old Version = %d.%d, new version = %d.%d\n",
+		ntohl(uv.epoch), ntohl(uv.counter),
+		ntohl(uh->version.epoch), ntohl(uh->version.counter));
+    }
+    close (dbase_fd);
+    exit (0);
+}
+
+int display_entry (offset)
+int offset;
+{
+    register int i;
+
+    lseek (dbase_fd, offset+HDRSIZE, L_SET);
+    read(dbase_fd, &pre, sizeof(struct prentry));
+
+    fix_pre(&pre);
+
+    if ((pre.flags & PRFREE) == 0) {
+	if (pre.flags & PRGRP) {
+	    if (flags & DO_GRP)
+		add_group(pre.id);
+	} else {
+	    if (print_id(pre.id) && (flags&DO_USR))
+		fprintf(dfp, FMT_BASE,
+			pre.name, pre.flags, pre.ngroups,
+			pre.id, pre.owner, pre.creator);
+	    checkin(&pre);
+	}
+    }
+    return(nflag ? pre.nextName: pre.nextID);
+}
+
+void add_group(id)
+    long id;
+{
+    struct grp_list *g;
+    register long i;
+
+    i = grp_count++ % 1024;
+    if (i == 0) {
+	g = (struct grp_list *)malloc(sizeof(struct grp_list));
+	g->next = grp_head;
+	grp_head = g;
+    }
+    g = grp_head;
+    g->groups[i] = id;
+}
+
+void display_groups()
+{
+    register int i, id;
+    struct grp_list *g;
+
+    g = grp_head;
+    while (grp_count--) {
+	i = grp_count%1024;
+	id = g->groups[i];
+	display_group(id);
+	if (i==0) {
+	    grp_head = g->next;
+	    free(g);
+	    g = grp_head;
+	}
+    }
+}
+
+void display_group(id)
+    int id;
+{
+    register int i, offset;
+    int print_grp = 0;
+
+    offset = ntohl(prh.idHash[IDHash(id)]);
+    while (offset) {
+	lseek(dbase_fd, offset+HDRSIZE, L_SET);
+	if (read(dbase_fd, &pre, sizeof(struct prentry)) < 0) {
+	    fprintf(stderr, "ptdump: read i/o error: %s\n",
+		    strerror(errno));
+	    exit (1);
+	}
+	fix_pre(&pre);
+	if (pre.id == id)
+	    break;
+	offset = pre.nextID;
+    }
+
+    if (print_id(id)) {
+	fprintf(dfp, FMT_BASE,
+		pre.name, pre.flags, pre.ngroups,
+		pre.id, pre.owner, pre.creator);
+	print_grp = 1;
+    }
+
+    if ((flags&DO_MEM) == 0)
+	return;
+
+    for (i=0; i<PRSIZE; i++) {
+	if ((id=pre.entries[i]) == 0)
+	    break;
+	if (id==PRBADID) continue;
+	if (print_id(id) || print_grp==1) {
+	    if (print_grp==0) {
+		fprintf(dfp, FMT_BASE,
+			pre.name, pre.flags, pre.ngroups,
+			pre.id, pre.owner, pre.creator);
+		print_grp = 2;
+	    }
+	    fprintf(dfp, FMT_MEM, id_to_name(id), id);
+	}
+    }
+    if (i == PRSIZE) {
+	offset = pre.next;
+	while (offset) {
+	    lseek(dbase_fd, offset+HDRSIZE, L_SET);
+	    read(dbase_fd, &prco, sizeof(struct contentry));
+	    prco.next = ntohl(prco.next);
+	    for (i = 0; i < COSIZE; i++) {
+		prco.entries[i] = ntohl(prco.entries[i]);
+		if ((id=prco.entries[i]) == 0)
+		    break;
+		if (id==PRBADID) continue;
+		if (print_id(id) || print_grp==1) {
+		    if (print_grp==0) {
+			fprintf(dfp, FMT_BASE,
+				pre.name, pre.flags, pre.ngroups,
+				pre.id, pre.owner, pre.creator);
+			print_grp = 2;
+		    }
+		    fprintf(dfp, FMT_MEM, id_to_name(id), id);
+		}
+	    }
+	    if ((i == COSIZE) && prco.next)
+		offset = prco.next;
+	    else offset = 0;
+	}
+    }
+}
+
+void fix_pre(pre)
+    struct prentry *pre;
+{
+    register int i;
+    
+    pre->flags = ntohl(pre->flags);
+    pre->id = ntohl(pre->id);
+    pre->cellid = ntohl(pre->cellid);
+    pre->next = ntohl(pre->next);
+    pre->nextID = ntohl(pre->nextID);
+    pre->nextName = ntohl(pre->nextName);
+    pre->owner = ntohl(pre->owner);
+    pre->creator = ntohl(pre->creator);
+    pre->ngroups = ntohl(pre->ngroups);
+    pre->nusers = ntohl(pre->nusers);
+    pre->count = ntohl(pre->count);
+    pre->instance = ntohl(pre->instance);
+    pre->owned = ntohl(pre->owned);
+    pre->nextOwned = ntohl(pre->nextOwned);
+    pre->parent = ntohl(pre->parent);
+    pre->sibling = ntohl(pre->sibling);
+    pre->child = ntohl(pre->child);
+    for (i = 0; i < PRSIZE; i++) {
+	pre->entries[i] = ntohl(pre->entries[i]);
+    }
+}
+
+char *id_to_name(id)
+int id;
+{
+    register int offset;
+    static struct prentry pre;
+    char *name;
+
+    name = check_core(id);
+    if (name) return(name);
+    offset = ntohl(prh.idHash[IDHash(id)]);
+    while (offset) {
+	lseek(dbase_fd, offset+HDRSIZE, L_SET);
+	if (read(dbase_fd, &pre, sizeof(struct prentry)) < 0) {
+	    fprintf(stderr, "ptdump: read i/o error: %s\n",
+		    sys_errlist[errno]);
+	    exit (1);
+	}
+	pre.id = ntohl(pre.id);
+	if (pre.id == id) {
+	    name = checkin(&pre);
+	    return(name);
+	}
+	offset = ntohl(pre.nextID);
+    }
+    return 0;
+}
+
+char *checkin(pre)
+struct prentry *pre;
+{
+    struct hash_entry *he, *last;
+    register int id;
+
+    id = pre->id;
+    last = (struct hash_entry *)0;
+    he = hat[IDHash(id)];
+    while (he) {
+	if (id == he->h_id) return(he->h_name);
+	last = he;
+	he = he->next;
+    }
+    he = (struct hash_entry *)malloc(sizeof(struct hash_entry));
+    if (he == 0) {
+	fprintf(stderr, "ptdump: No Memory for internal hash table.\n");
+	exit (1);
+    }
+    he->h_id = id;
+    he->next = (struct hash_entry *)0;
+    strncpy(he->h_name, pre->name, PR_MAXNAMELEN);
+    if (last == (struct hash_entry *)0) hat[IDHash(id)] = he;
+    else last->next = he;
+    return(he->h_name);
+}
+
+char *check_core(id)
+register int id;
+{
+    struct hash_entry *he;
+    he = hat[IDHash(id)];
+    while (he) {
+	if (id == he->h_id) return(he->h_name);
+	he = he->next;
+    }
+    return 0;
+}
--- debathena-moira-4.0.0+cvs20080304.orig/afssync/pt_util.c
+++ debathena-moira-4.0.0+cvs20080304/afssync/pt_util.c
@@ -0,0 +1,1199 @@
+/*
+ *
+ * pt_util: Program to dump the AFS protection server database
+ *         into an ascii file.
+ *
+ *	Assumptions: We *cheat* here and read the datafile directly, ie.
+ *	             not going through the ubik distributed data manager.
+ *		     therefore the database must be quiescent for the
+ *		     output of this program to be valid.
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <sys/file.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <afs/param.h>
+#include <lock.h>
+#include <netinet/in.h>
+#define UBIK_INTERNALS
+#include <ubik.h>
+#include <rx/xdr.h>
+#include <rx/rx.h>
+#include "ptint.h"
+#include "ptserver.h"
+#include "pterror.h"
+#include "vis.h"
+
+#define IDHash(x) (abs(x) % HASHSIZE)
+
+int display_entry(int offset);
+int print_id(int id);
+void add_group(long id);
+void display_groups(void);
+void display_group(int id);
+void fix_pre(struct prentry *pre);
+char *checkin(struct prentry *pre);
+char *check_core(register int id);
+char *id_to_name(int id);
+
+struct hash_entry {
+    char h_name[PR_MAXNAMELEN];
+    int h_id;
+    struct hash_entry *next;
+};
+struct hash_entry *hat[HASHSIZE];
+
+static struct contentry prco;
+static struct prentry pre;
+static struct prheader prh;
+static struct ubik_version uv;
+
+struct grp_list {
+    struct grp_list	*next;
+    long		groups[1024];
+};
+static struct grp_list *grp_head=0;
+static long grp_count=0;
+
+struct usr_list {
+    struct usr_list *next;
+    char name[PR_MAXNAMELEN];
+    long uid;
+};
+static struct usr_list *usr_head=0;
+
+char buffer[1024];
+int dbase_fd;
+FILE *dfp;
+
+#define FMT_BASE "%-10s %d/%d %d %d %d\n"
+#define FMT_MEM  "   %-8s %d\n"
+
+#define DO_USR 1
+#define DO_GRP 2
+#define DO_MEM 4
+#define DO_SYS 8
+#define DO_OTR 16
+
+int nflag = 0;
+int wflag = 0;
+int flags = 0;
+
+int main(int argc, char **argv)
+{
+    register int i;
+    register long code;
+    long cc, upos, gpos;
+    struct prentry uentry, gentry;
+    struct ubik_hdr *uh;
+    char *dfile = 0;
+    char *pfile = "/usr/afs/db/prdb.DB0";
+    char *str;
+    
+    while ((cc = getopt(argc, argv, "wugmxsnp:d:")) != EOF) {
+	switch (cc) {
+	case 'p':
+	    pfile = optarg;
+	    break;
+	case 'd':
+	    dfile = optarg;
+	    break;
+	case 'n':
+	    nflag++;
+	    break;
+	case 'w':
+	    wflag++;
+	    break;
+	case 'u':
+	    flags |= DO_USR;
+	    break;
+	case 'm':
+	    flags |= (DO_GRP|DO_MEM);
+	    break;
+	case 'g':
+	    flags |= DO_GRP;
+	    break;
+	case 's':
+	    flags |= DO_SYS;
+	    break;
+	case 'x':
+	    flags |= DO_OTR;
+	    break;
+	default:
+	    fprintf(stderr,
+		    "Usage: pt_util [options] [-d data] [-p prdb]\n");
+	    fputs("  Options:\n", stderr);
+	    fputs("    -w  Update prdb with contents of data file\n", stderr);
+	    fputs("    -u  Display users\n", stderr);
+	    fputs("    -g  Display groups\n", stderr);
+	    fputs("    -m  Display group members\n", stderr);
+	    fputs("    -n  Follow name hash chains (not id hashes)\n", stderr);
+	    fputs("    -s  Display only system (Moira) data\n", stderr);
+	    fputs("    -x  Display extra users/groups\n", stderr);
+	    exit(1);
+	}
+    }
+    if ((dbase_fd = open(pfile, wflag ? O_RDWR : O_RDONLY, 0600)) < 0) {
+	fprintf(stderr, "pt_util: cannot open %s: %s\n",
+		pfile, strerror(errno));
+	exit (1);
+    }
+    if (read(dbase_fd, buffer, HDRSIZE) < 0) {
+	fprintf(stderr, "pt_util: error reading %s: %s\n",
+		pfile, strerror(errno));
+	exit (1);
+    }
+
+    if (dfile) {
+	if ((dfp = fopen(dfile, wflag ? "r" : "w")) == 0) {
+	    fprintf(stderr, "pt_util: error opening %s: %s\n",
+		    dfile, strerror(errno));
+	    exit(1);
+	}
+    } else
+	dfp = (wflag ? stdin : stdout);
+
+    uh = (struct ubik_hdr *)buffer;
+    if (ntohl(uh->magic) != UBIK_MAGIC)
+	fprintf(stderr, "pt_util: %s: Bad UBIK_MAGIC. Is %x should be %x\n",
+		pfile, ntohl(uh->magic), UBIK_MAGIC);
+    memcpy(&uv, &uh->version, sizeof(struct ubik_version));
+    if (wflag && uv.epoch==0 && uv.counter==0) {
+	uv.epoch=2; /* a ubik version of 0 or 1 has special meaning */
+	memcpy(&uh->version, &uv, sizeof(struct ubik_version));
+	lseek(dbase_fd, 0, SEEK_SET);
+	if (write(dbase_fd, buffer, HDRSIZE) < 0) {
+	    fprintf(stderr, "pt_util: error writing ubik version to %s: %s\n",
+		    pfile, strerror(errno));
+	    exit (1);
+	}
+    }
+    fprintf(stderr, "Ubik Version is: %d.%d\n",
+	    uv.epoch, uv.counter);
+    if (read(dbase_fd, &prh, sizeof(struct prheader)) < 0) {
+	fprintf(stderr, "pt_util: error reading %s: %s\n",
+		pfile, strerror(errno));
+	exit (1);
+    }
+
+    Initdb();
+    initialize_pt_error_table();
+
+    if (wflag) {
+	struct usr_list *u;
+
+	while(fgets(buffer, sizeof(buffer), dfp)) {
+	    int id, oid, cid, flags, quota, uid;
+	    char name[PR_MAXNAMELEN], mem[PR_MAXNAMELEN];
+
+	    if (isspace(*buffer)) {
+		sscanf(buffer, "%s %d", mem, &uid);
+
+		for (u=usr_head; u; u=u->next)
+		    if (u->uid && u->uid==uid) break;
+		if (u) {
+		    /* Add user - deferred because it is probably foreign */
+		    u->uid = 0;
+		    if (FindByID(0, uid))
+			code = PRIDEXIST;
+		    else {
+			if (!code && (flags&(PRGRP|PRQUOTA))==(PRGRP|PRQUOTA)){
+			    gentry.ngroups++;
+			    code = pr_WriteEntry(0,0,gpos,&gentry);
+			    if (code)
+				fprintf(stderr, "Error setting group count on %s: %s\n",
+					name, error_message(code));
+			}
+			code = CreateEntry
+			    (0, u->name, &uid, 1/*idflag*/, 1/*gflag*/,
+			     SYSADMINID/*oid*/, SYSADMINID/*cid*/);
+		    }
+		    if (code)
+			fprintf(stderr, "Error while creating %s: %s\n",
+				u->name, error_message(code));
+		    continue;
+		}
+		/* Add user to group */
+		if (id==ANYUSERID || id==AUTHUSERID || uid==ANONYMOUSID) {
+		    code = PRPERM;
+		} else if ((upos=FindByID(0,uid)) && (gpos=FindByID(0,id))) {
+		    code = pr_ReadEntry(0,0,upos,&uentry);
+		    if (!code) code = pr_ReadEntry(0,0,gpos,&gentry);
+		    if (!code) code = AddToEntry (0, &gentry, gpos, uid);
+		    if (!code) code = AddToEntry (0, &uentry, upos, id);
+		} else
+		    code = PRNOENT;
+
+		if (code)
+		    fprintf(stderr, "Error while adding %s to %s: %s\n",
+			    mem, name, error_message(code));
+	    } else {
+		sscanf(buffer, "%s %d/%d %d %d %d",
+		       name, &flags, &quota, &id, &oid, &cid);
+
+		str = malloc(strlen(name) + 1);
+		if (!str)
+		  {
+		    fprintf(stderr, "malloc failed!");
+		    exit(1);
+		  }
+		strunvis(str, name);
+		strncpy(name, str, PR_MAXNAMELEN);
+		name[PR_MAXNAMELEN] = '\0';
+		if (FindByID(0, id))
+		    code = PRIDEXIST;
+		else
+		    code = CreateEntry(0, name, &id, 1/*idflag*/,
+				       flags&PRGRP, oid, cid);
+		if (code == PRBADNAM) {
+		    u = (struct usr_list *)malloc(sizeof(struct usr_list));
+		    u->next = usr_head;
+		    u->uid = id;
+		    strcpy(u->name, name);
+		    usr_head = u;
+		} else
+		if (code) {
+		    fprintf(stderr, "Error while creating %s: %s\n",
+			    name, error_message(code));
+		} else if ((flags&PRACCESS) ||
+			   (flags&(PRGRP|PRQUOTA))==(PRGRP|PRQUOTA)) {
+		    gpos = FindByID(0, id);
+		    code = pr_ReadEntry(0,0,gpos,&gentry);
+		    if (!code) {
+			gentry.flags = flags;
+			gentry.ngroups = quota;
+			code = pr_WriteEntry(0,0,gpos,&gentry);
+		    }
+		    if (code)
+			fprintf(stderr,"Error while setting flags on %s: %s\n",
+				name, error_message(code));
+		}
+	    }
+	}
+	for (u=usr_head; u; u=u->next)
+	    if (u->uid)
+		fprintf(stderr, "Error while creating %s: %s\n",
+			u->name, error_message(PRBADNAM));
+    } else {
+	for (i = 0; i < HASHSIZE; i++) {
+	    upos = nflag ? ntohl(prh.nameHash[i]) : ntohl(prh.idHash[i]);
+	    while (upos)
+		upos = display_entry(upos);
+	}
+	if (flags & DO_GRP)
+	    display_groups();
+    }
+
+    lseek (dbase_fd, 0, L_SET);		/* rewind to beginning of file */
+    if (read(dbase_fd, buffer, HDRSIZE) < 0) {
+	fprintf(stderr, "pt_util: error reading %s: %s\n",
+		pfile, strerror(errno));
+	exit (1);
+    }
+    uh = (struct ubik_hdr *)buffer;
+    if ((uh->version.epoch != uv.epoch) ||
+	(uh->version.counter != uv.counter)) {
+	fprintf(stderr, "pt_util: Ubik Version number changed during execution.\n");
+	fprintf(stderr, "Old Version = %d.%d, new version = %d.%d\n",
+		uv.epoch, uv.counter, uh->version.epoch,
+		uh->version.counter);
+    }
+    close (dbase_fd);
+    exit (0);
+}
+
+int display_entry(int offset)
+{
+    register int i;
+
+    lseek (dbase_fd, offset+HDRSIZE, L_SET);
+    read(dbase_fd, &pre, sizeof(struct prentry));
+
+    fix_pre(&pre);
+
+    if ((pre.flags & PRFREE) == 0) {
+	if (pre.flags & PRGRP) {
+	    if (flags & DO_GRP)
+		add_group(pre.id);
+	} else {
+	    if (print_id(pre.id) && (flags&DO_USR))
+		fprintf(dfp, FMT_BASE,
+			pre.name, pre.flags, pre.ngroups,
+			pre.id, pre.owner, pre.creator);
+	    checkin(&pre);
+	}
+    }
+    return(nflag ? pre.nextName: pre.nextID);
+}
+
+void add_group(long id)
+{
+    struct grp_list *g;
+    register long i;
+
+    i = grp_count++ % 1024;
+    if (i == 0) {
+	g = (struct grp_list *)malloc(sizeof(struct grp_list));
+	g->next = grp_head;
+	grp_head = g;
+    }
+    g = grp_head;
+    g->groups[i] = id;
+}
+
+void display_groups(void)
+{
+    register int i, id;
+    struct grp_list *g;
+
+    g = grp_head;
+    while (grp_count--) {
+	i = grp_count%1024;
+	id = g->groups[i];
+	display_group(id);
+	if (i==0) {
+	    grp_head = g->next;
+	    free(g);
+	    g = grp_head;
+	}
+    }
+}
+
+void display_group(int id)
+{
+    register int i, offset;
+    int print_grp = 0;
+
+    offset = ntohl(prh.idHash[IDHash(id)]);
+    while (offset) {
+	lseek(dbase_fd, offset+HDRSIZE, L_SET);
+	if (read(dbase_fd, &pre, sizeof(struct prentry)) < 0) {
+	    fprintf(stderr, "pt_util: read i/o error: %s\n",
+		    strerror(errno));
+	    exit (1);
+	}
+	fix_pre(&pre);
+	if (pre.id == id)
+	    break;
+	offset = pre.nextID;
+    }
+
+    if (print_id(id)) {
+	fprintf(dfp, FMT_BASE,
+		pre.name, pre.flags, pre.ngroups,
+		pre.id, pre.owner, pre.creator);
+	print_grp = 1;
+    }
+
+    if ((flags&DO_MEM) == 0)
+	return;
+
+    for (i=0; i<PRSIZE; i++) {
+	if ((id=pre.entries[i]) == 0)
+	    break;
+	if (id==PRBADID) continue;
+	if (print_id(id) || print_grp==1) {
+	    if (print_grp==0) {
+		fprintf(dfp, FMT_BASE,
+			pre.name, pre.flags, pre.ngroups,
+			pre.id, pre.owner, pre.creator);
+		print_grp = 2;
+	    }
+	    fprintf(dfp, FMT_MEM, id_to_name(id), id);
+	}
+    }
+    if (i == PRSIZE) {
+	offset = pre.next;
+	while (offset) {
+	    lseek(dbase_fd, offset+HDRSIZE, L_SET);
+	    read(dbase_fd, &prco, sizeof(struct contentry));
+	    prco.next = ntohl(prco.next);
+	    for (i = 0; i < COSIZE; i++) {
+		prco.entries[i] = ntohl(prco.entries[i]);
+		if ((id=prco.entries[i]) == 0)
+		    break;
+		if (id==PRBADID) continue;
+		if (print_id(id) || print_grp==1) {
+		    if (print_grp==0) {
+			fprintf(dfp, FMT_BASE,
+				pre.name, pre.flags, pre.ngroups,
+				pre.id, pre.owner, pre.creator);
+			print_grp = 2;
+		    }
+		    fprintf(dfp, FMT_MEM, id_to_name(id), id);
+		}
+	    }
+	    if ((i == COSIZE) && prco.next)
+		offset = prco.next;
+	    else offset = 0;
+	}
+    }
+}
+
+void fix_pre(struct prentry *pre)
+{
+    register int i;
+    char *str = malloc(4 * strlen(pre->name) + 1);
+
+    if (!str)
+      {
+	fprintf(stderr, "malloc failed in fix_pre()!");
+	exit(1);
+      }
+    strvis(str, pre->name, VIS_WHITE);
+    if (strlen(str) > PR_MAXNAMELEN) 
+      {
+	fprintf(stderr, "encoding greater than PR_MAXNAMELEN!\n");
+	fprintf(stderr, "groupname %s will not be encoded!\n", pre->name);
+      }
+    else 
+      {
+	strncpy(pre->name, str, PR_MAXNAMELEN);
+	pre->name[PR_MAXNAMELEN] = '\0';
+      }
+    pre->flags = ntohl(pre->flags);
+    pre->id = ntohl(pre->id);
+    pre->cellid = ntohl(pre->cellid);
+    pre->next = ntohl(pre->next);
+    pre->nextID = ntohl(pre->nextID);
+    pre->nextName = ntohl(pre->nextName);
+    pre->owner = ntohl(pre->owner);
+    pre->creator = ntohl(pre->creator);
+    pre->ngroups = ntohl(pre->ngroups);
+    pre->nusers = ntohl(pre->nusers);
+    pre->count = ntohl(pre->count);
+    pre->instance = ntohl(pre->instance);
+    pre->owned = ntohl(pre->owned);
+    pre->nextOwned = ntohl(pre->nextOwned);
+    pre->parent = ntohl(pre->parent);
+    pre->sibling = ntohl(pre->sibling);
+    pre->child = ntohl(pre->child);
+    for (i = 0; i < PRSIZE; i++) {
+	pre->entries[i] = ntohl(pre->entries[i]);
+    }
+}
+
+char *id_to_name(int id)
+{
+    register int offset;
+    static struct prentry pre;
+    char *name;
+
+    name = check_core(id);
+    if (name) return(name);
+    offset = ntohl(prh.idHash[IDHash(id)]);
+    while (offset) {
+	lseek(dbase_fd, offset+HDRSIZE, L_SET);
+	if (read(dbase_fd, &pre, sizeof(struct prentry)) < 0) {
+	    fprintf(stderr, "pt_util: read i/o error: %s\n",
+		    strerror(errno));
+	    exit (1);
+	}
+	pre.id = ntohl(pre.id);
+	if (pre.id == id) {
+	    name = checkin(&pre);
+	    return(name);
+	}
+	offset = ntohl(pre.nextID);
+    }
+    return 0;
+}
+
+char *checkin(struct prentry *pre)
+{
+    struct hash_entry *he, *last;
+    register int id;
+
+    id = pre->id;
+    last = (struct hash_entry *)0;
+    he = hat[IDHash(id)];
+    while (he) {
+	if (id == he->h_id) return(he->h_name);
+	last = he;
+	he = he->next;
+    }
+    he = (struct hash_entry *)malloc(sizeof(struct hash_entry));
+    if (he == 0) {
+	fprintf(stderr, "pt_util: No Memory for internal hash table.\n");
+	exit (1);
+    }
+    he->h_id = id;
+    he->next = (struct hash_entry *)0;
+    strncpy(he->h_name, pre->name, PR_MAXNAMELEN);
+    if (last == (struct hash_entry *)0) hat[IDHash(id)] = he;
+    else last->next = he;
+    return(he->h_name);
+}
+
+char *check_core(register int id)
+{
+    struct hash_entry *he;
+    he = hat[IDHash(id)];
+    while (he) {
+	if (id == he->h_id) return(he->h_name);
+	he = he->next;
+    }
+    return 0;
+}
+
+/* returns 1 if the id value should be printered, otherwise 0 */
+int print_id(int id)
+{
+  /* process system (Moira) users */
+  if (flags & DO_SYS)
+    {
+      /* hard-coded list of IDs in the system id space that aren't actually
+       * system users.  Skip them here.  Mmm, legacies.
+       */
+      switch (id)
+	{
+	case -65541:
+	case -65542:
+	case -65544:
+	case -65546:
+	case -65548:
+	case -65549:
+	case -65551:
+	case -65557:
+	case -65563:
+	case -65574:
+	case -65576:
+	case -65578:
+	case -65579:
+	case -65582:
+	case -97536:
+	case -97537:
+	case -97538:
+	case -98766:
+	case -98775:
+	case -98781:
+	case -98782:
+	case -98783:
+	case -98784:
+	case -98785:
+	case -98786:
+	case -98787:
+	case -98788:
+	case -98789:
+	case -98792:
+	case -98813:
+	case -98815:
+	case -98816:
+	case -98818:
+	case -98819:
+	case -98820:
+	case -98821:
+	case -98828:
+	case -98829:
+	case -98830:
+	case -98835:
+	case -98836:
+	case -98837:
+	case -98841:
+	case -98842:
+	case -98844:
+	case -98845:
+	case -98846:
+	case -98847:
+	case -98848:
+	case -98849:
+	case -98851:
+	case -98854:
+	case -98855:
+	case -98856:
+	case -98857:
+	case -98859:
+	case -98867:
+	case -98868:
+	case -98869:
+	case -98870:
+	case -98871:
+	case -98873:
+	case -98878:
+	case -98879:
+	case -98883:
+	case -98884:
+	case -98885:
+	case -98888:
+	case -98891:
+	case -98898:
+	case -98903:
+	case -98905:
+	case -98914:
+	case -98918:
+	case -98919:
+	case -98920:
+	case -98923:
+	case -98927:
+	case -98941:
+	case -98942:
+	case -98945:
+	case -98948:
+	case -98949:
+	case -98951:
+	case -98952:
+	case -98953:
+	case -98956:
+	case -98957:
+	case -98960:
+	case -98961:
+	case -98963:
+	case -98966:
+	case -98994:
+	case -98996:
+	case -98998:
+	case -99000:
+	case -99001:
+	case -99002:
+	case -99003:
+	case -99004:
+	case -99005:
+	case -99006:
+	case -99007:
+	case -99008:
+	case -99009:
+	case -99010:
+	case -99011:
+	case -99012:
+	case -99013:
+	case -99014:
+	case -99015:
+	case -99016:
+	case -99017:
+	case -99018:
+	case -99019:
+	case -99023:
+	case -99029:
+	case -99030:
+	case -99042:
+	case -99048:
+	case -99056:
+	case -99057:
+	case -99058:
+	case -99059:
+	case -99063:
+	case -99064:
+	case -99076:
+	case -99079:
+	case -99090:
+	case -99091:
+	case -99105:
+	case -99106:
+	case -99113:
+	case -99114:
+	case -99115:
+	case -99116:
+	case -99118:
+	case -99120:
+	case -99121:
+	case -99129:
+	case -99130:
+	case -99131:
+	case -99133:
+	case -99146:
+	case -99150:
+	case -99153:
+	case -99154:
+	case -99193:
+	case -99194:
+	case -99200:
+	case -99205:
+	case -99211:
+	case -99214:
+	case -99218:
+	case -99220:
+	case -99223:
+	case -99224:
+	case -99225:
+	case -99233:
+	case -99234:
+	case -99236:
+	case -99237:
+	case -99242:
+	case -99245:
+	case -99250:
+	case -99252:
+	case -99253:
+	case -99254:
+	case -99255:
+	case -99259:
+	case -99260:
+	case -99263:
+	case -99264:
+	case -99267:
+	case -99284:
+	case -99287:
+	case -99289:
+	case -99295:
+	case -99297:
+	case -99307:
+	case -99308:
+	case -99309:
+	case -99310:
+	case -99311:
+	case -99315:
+	case -99317:
+	case -99327:
+	case -99334:
+	case -99344:
+	case -99348:
+	case -99349:
+	case -99354:
+	case -99366:
+	case -99367:
+	case -99370:
+	case -99371:
+	case -99372:
+	case -99373:
+	case -99377:
+	case -99378:
+	case -99379:
+	case 65613:
+	case 65678:
+	case 65770:
+	case 65896:
+	case 65971:
+	case 65987:
+	case 66011:
+	case 66114:
+	case 66142:
+	case 67145:
+	case 67299:
+	case 67393:
+	case 67669:
+	case 67712:
+	case 67903:
+	case 68276:
+	case 68421:
+	case 68467:
+	case 69005:
+	case 69143:
+	case 69234:
+	case 69611:
+	case 70141:
+	case 70481:
+	case 71468:
+	case 71559:
+	case 71689:
+	case 72203:
+	case 72775:
+	case 72799:
+	case 73319:
+	case 73348:
+	case 73578:
+	case 73642:
+	case 73656:
+	case 74424:
+	case 74610:
+	case 75067:
+	case 75169:
+	case 75197:
+	case 75332:
+	case 75717:
+	case 76261:
+	case 76322:
+	case 76341:
+	case 76529:
+	case 76546:
+	case 76747:
+	case 76804:
+	case 77353:
+	case 77409:
+	case 77800:
+	case 78720:
+	case 80148:
+	case 80176:
+	case 80422:
+	case 80533:
+	case 80856:
+	case 81342:
+	case 82058:
+	case 82279:
+	case 82304:
+	case 82605:
+	case 82611:
+	case 84255:
+	case 84476:
+	case 85005:
+	case 85309:
+	case 85426:
+	case 85530:
+	case 87306:
+	case 88377:
+	case 89960:
+	case 90782:
+	case 92388:
+	case 92990:
+	case 94724:
+	case 95044:
+	case 95057:
+	case 95969:
+	case 96863:
+	case 97354:
+	case 97538:
+	case 97540:
+	case 97542:
+	case 97544:
+	case 97545:
+	case 97546:
+	case 97547:
+	case 97556:
+	case 97559:
+	case 97560:
+	case 97570:
+	case 99070:
+	case 99071:
+	case 99072:
+	case 101061:
+	case 101502:
+	case 102042:
+	case 103500:
+	case 106026:
+	case 119873:
+	case 127811:
+	case 128401:
+	case 128906:
+	case 130756:
+	case 130781:
+	  return 0;
+	  break;
+	}
+      if (id > -131073 && id < 131073)
+	return 1;
+      else
+	return 0;
+    }
+  /* process non-system (not in Moira) users */
+  else if (flags & DO_OTR)
+    {
+      /* hard-coded list of IDs in the system id space that aren't actually
+       * system users.  Print them here.  Mmm, legacies.
+       */
+      switch (id)
+	{
+	case -65541:
+	case -65542:
+	case -65544:
+	case -65546:
+	case -65548:
+	case -65549:
+	case -65551:
+	case -65557:
+	case -65563:
+	case -65574:
+	case -65576:
+	case -65578:
+	case -65579:
+	case -65582:
+	case -97536:
+	case -97537:
+	case -97538:
+	case -98766:
+	case -98775:
+	case -98781:
+	case -98782:
+	case -98783:
+	case -98784:
+	case -98785:
+	case -98786:
+	case -98787:
+	case -98788:
+	case -98789:
+	case -98792:
+	case -98813:
+	case -98815:
+	case -98816:
+	case -98818:
+	case -98819:
+	case -98820:
+	case -98821:
+	case -98828:
+	case -98829:
+	case -98830:
+	case -98835:
+	case -98836:
+	case -98837:
+	case -98841:
+	case -98842:
+	case -98844:
+	case -98845:
+	case -98846:
+	case -98847:
+	case -98848:
+	case -98849:
+	case -98851:
+	case -98854:
+	case -98855:
+	case -98856:
+	case -98857:
+	case -98859:
+	case -98867:
+	case -98868:
+	case -98869:
+	case -98870:
+	case -98871:
+	case -98873:
+	case -98878:
+	case -98879:
+	case -98883:
+	case -98884:
+	case -98885:
+	case -98888:
+	case -98891:
+	case -98898:
+	case -98903:
+	case -98905:
+	case -98914:
+	case -98918:
+	case -98919:
+	case -98920:
+	case -98923:
+	case -98927:
+	case -98941:
+	case -98942:
+	case -98945:
+	case -98948:
+	case -98949:
+	case -98951:
+	case -98952:
+	case -98953:
+	case -98956:
+	case -98957:
+	case -98960:
+	case -98961:
+	case -98963:
+	case -98966:
+	case -98994:
+	case -98996:
+	case -98998:
+	case -99000:
+	case -99001:
+	case -99002:
+	case -99003:
+	case -99004:
+	case -99005:
+	case -99006:
+	case -99007:
+	case -99008:
+	case -99009:
+	case -99010:
+	case -99011:
+	case -99012:
+	case -99013:
+	case -99014:
+	case -99015:
+	case -99016:
+	case -99017:
+	case -99018:
+	case -99019:
+	case -99023:
+	case -99029:
+	case -99030:
+	case -99042:
+	case -99048:
+	case -99056:
+	case -99057:
+	case -99058:
+	case -99059:
+	case -99063:
+	case -99064:
+	case -99076:
+	case -99079:
+	case -99090:
+	case -99091:
+	case -99105:
+	case -99106:
+	case -99113:
+	case -99114:
+	case -99115:
+	case -99116:
+	case -99118:
+	case -99120:
+	case -99121:
+	case -99129:
+	case -99130:
+	case -99131:
+	case -99133:
+	case -99146:
+	case -99150:
+	case -99153:
+	case -99154:
+	case -99193:
+	case -99194:
+	case -99200:
+	case -99205:
+	case -99211:
+	case -99214:
+	case -99218:
+	case -99220:
+	case -99223:
+	case -99224:
+	case -99225:
+	case -99233:
+	case -99234:
+	case -99236:
+	case -99237:
+	case -99242:
+	case -99245:
+	case -99250:
+	case -99252:
+	case -99253:
+	case -99254:
+	case -99255:
+	case -99259:
+	case -99260:
+	case -99263:
+	case -99264:
+	case -99267:
+	case -99284:
+	case -99287:
+	case -99289:
+	case -99295:
+	case -99297:
+	case -99307:
+	case -99308:
+	case -99309:
+	case -99310:
+	case -99311:
+	case -99315:
+	case -99317:
+	case -99327:
+	case -99334:
+	case -99344:
+	case -99348:
+	case -99349:
+	case -99354:
+	case -99366:
+	case -99367:
+	case -99370:
+	case -99371:
+	case -99372:
+	case -99373:
+	case -99377:
+	case -99378:
+	case -99379:
+	case 65613:
+	case 65678:
+	case 65770:
+	case 65896:
+	case 65971:
+	case 65987:
+	case 66011:
+	case 66114:
+	case 66142:
+	case 67145:
+	case 67299:
+	case 67393:
+	case 67669:
+	case 67712:
+	case 67903:
+	case 68276:
+	case 68421:
+	case 68467:
+	case 69005:
+	case 69143:
+	case 69234:
+	case 69611:
+	case 70141:
+	case 70481:
+	case 71468:
+	case 71559:
+	case 71689:
+	case 72203:
+	case 72775:
+	case 72799:
+	case 73319:
+	case 73348:
+	case 73578:
+	case 73642:
+	case 73656:
+	case 74424:
+	case 74610:
+	case 75067:
+	case 75169:
+	case 75197:
+	case 75332:
+	case 75717:
+	case 76261:
+	case 76322:
+	case 76341:
+	case 76529:
+	case 76546:
+	case 76747:
+	case 76804:
+	case 77353:
+	case 77409:
+	case 77800:
+	case 78720:
+	case 80148:
+	case 80176:
+	case 80422:
+	case 80533:
+	case 80856:
+	case 81342:
+	case 82058:
+	case 82279:
+	case 82304:
+	case 82605:
+	case 82611:
+	case 84255:
+	case 84476:
+	case 85005:
+	case 85309:
+	case 85426:
+	case 85530:
+	case 87306:
+	case 88377:
+	case 89960:
+	case 90782:
+	case 92388:
+	case 92990:
+	case 94724:
+	case 95044:
+	case 95057:
+	case 95969:
+	case 96863:
+	case 97354:
+	case 97538:
+	case 97540:
+	case 97542:
+	case 97544:
+	case 97545:
+	case 97546:
+	case 97547:
+	case 97556:
+	case 97559:
+	case 97560:
+	case 97570:
+	case 99070:
+	case 99071:
+	case 99072:
+	case 101061:
+	case 101502:
+	case 102042:
+	case 103500:
+	case 106026:
+	case 119873:
+	case 127811:
+	case 128401:
+	case 128906:
+	case 130756:
+	case 130781:
+	  return 1;
+	  break;
+	}
+      if (id < -131072 || id > 131072)
+	return 1;
+      else
+	return 0;
+    }
+  /* neither flag set, don't do anything */
+  else
+    return 0;
+}
--- debathena-moira-4.0.0+cvs20080304.orig/afssync/pt_util.pl
+++ debathena-moira-4.0.0+cvs20080304/afssync/pt_util.pl
@@ -0,0 +1,50 @@
+#!/usr/athena/bin/perl
+
+while ($_ = <STDIN>) {
+    if (/^\s/) {
+	$members{$who} = $members{$who} . $_;
+	$mcount{$who}++;
+	next;
+    }
+    ($f,$f,$who,$own) = split(/\s+/, $_);
+    $data{$who} = $_;
+}
+
+# Do system:authuser@cell groups
+for (keys %data) {
+    next unless ($data{$_} =~ /^system:authuser@/);
+    ($name, $attr, $id, $oid, $cid) = split(/\s+/, $data{$_});
+    ($flags, $mcount) = split(/\//, $attr);
+    $mcount += $mcount{$_};
+    print "$name $flags/$mcount $id $oid $cid\n";
+    delete $data{$_};
+}
+
+# Do users
+for (keys %data) {
+    next if ($_ < 0);
+    print $data{$_};
+    delete $data{$_};
+}
+
+# Now do all the lists
+$x = 1;
+while ((@keys = keys %data)+0 && $x) {
+    $x = 0;
+    for $key (keys %data) {
+	($f,$f,$who,$own) = split(/\s+/, $data{$key});
+	next if ($who!=$own && $data{$own});
+	$x = 1;
+	print $data{$key};
+	print $members{$key} if ($members{$key});
+	delete $data{$key};
+	delete $members{$key} if ($members{$key});
+    }
+}
+if (@keys+0) {
+    print STDERR "Unprocessed:\n";
+    for (keys %data) {
+	$f = split(/\s+/, $data{$_});
+	print STDERR "\t$f ($_)\n";
+    }
+}
--- debathena-moira-4.0.0+cvs20080304.orig/afssync/ptdump.c
+++ debathena-moira-4.0.0+cvs20080304/afssync/ptdump.c
@@ -0,0 +1,273 @@
+/*
+ *
+ * ptdump: Program to dump the AFS protection server database
+ *         into an ascii file.
+ *
+ *	Assumptions: We *cheat* here and read the datafile directly, ie.
+ *	             not going through the ubik distributed data manager.
+ *		     therefore the database must be quiescent for the
+ *		     output of this program to be valid.
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <sys/file.h>
+#include <lock.h>
+#include <netinet/in.h>
+#define UBIK_INTERNALS
+#include <ubik.h>
+#include <rx/xdr.h>
+#include <rx/rx.h>
+#include <afs/ptint.h>
+#include <afs/ptserver.h>
+extern char *optarg;
+extern int optind;
+extern int errno;
+extern char *sys_errlist[];
+struct prheader prh;
+struct prentry pre;
+struct ubik_version uv;
+char buffer[1024];
+int grpflag, nmflg, cflag;
+
+main(argc, argv)
+int argc;
+char **argv;
+{
+    int cc;
+    int fd, offset;
+    register int i;
+    char file[512];
+    register struct ubik_hdr *uh;
+    int didit;
+    setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
+    strcpy(file, "/usr/afs/db/prdb.DB0");
+    while ((cc = getopt(argc, argv, "f:gnc")) != EOF) {
+	switch (cc) {
+	case 'f':
+	    strncpy (file, optarg, sizeof(file));
+	    break;
+	case 'g':
+	    grpflag++;
+	    break;
+	case 'c':
+	    cflag++;
+	    break;
+	case 'n':
+	    nmflg++;		/* Use the Name hash chain */
+	    break;
+	default:
+	    fprintf(stderr, "ptdump: -%c: unknown option\n", cc);
+	    break;
+	}
+    }
+    if (cflag && !grpflag) {
+	fprintf(stderr, "ptdump: -c requires -g flag.\n");
+	exit (1);
+    }
+    if ((fd = open(file, O_RDONLY, 0600)) < 0) {
+	fprintf(stderr, "ptdump: cannot open %s: %s\n",
+		file, sys_errlist[errno]);
+	exit (1);
+    }
+    if (read(fd, buffer, HDRSIZE) < 0) {
+	fprintf(stderr, "ptdump: error reading %s: %s\n",
+		file, sys_errlist[errno]);
+	exit (1);
+    }
+    uh = (struct ubik_hdr *)buffer;
+    if (ntohl(uh->magic) != UBIK_MAGIC)
+	fprintf(stderr, "ptdump: %s: Bad UBIK_MAGIC. Is %x should be %x\n",
+		file, ntohl(uh->magic), UBIK_MAGIC);
+    memcpy(&uv, &uh->version, sizeof(struct ubik_version));
+    fprintf(stderr, "Ubik Version is: %D.%d\n",
+	    uv.epoch, uv.counter);
+    if (read(fd, &prh, sizeof(struct prheader)) < 0) {
+	fprintf(stderr, "ptdump: error reading %s: %s\n",
+		file, sys_errlist[errno]);
+	exit (1);
+    }
+    for (i = 0; i < HASHSIZE; i++) {
+	offset = nmflg ? ntohl(prh.nameHash[i]) : ntohl(prh.idHash[i]);
+	didit = 0;
+	while (offset)
+	    offset = display_entry(offset, fd, &didit);
+    }
+    lseek (fd, 0, L_SET);		/* rewind to beginning of file */
+    if (read(fd, buffer, HDRSIZE) < 0) {
+	fprintf(stderr, "ptdump: error reading %s: %s\n",
+		file, sys_errlist[errno]);
+	exit (1);
+    }
+    uh = (struct ubik_hdr *)buffer;
+    if ((uh->version.epoch != uv.epoch) ||
+	(uh->version.counter != uv.counter)) {
+	fprintf(stderr, "ptdump: Ubik Version number changed during execution.\n");
+	fprintf(stderr, "Old Version = %D.%d, new version = %D.%d\n",
+		uv.epoch, uv.counter, uh->version.epoch,
+		uh->version.counter);
+    }
+    close (fd);
+    exit (0);
+}
+int display_entry (offset, fd, didit)
+int offset, fd;
+int *didit;
+{
+    void display_useful_groups();
+    char *checkin();
+    register int i;
+    lseek (fd, offset+HDRSIZE, L_SET);
+    read(fd, &pre, sizeof(struct prentry));
+    pre.flags = ntohl(pre.flags);
+    pre.id = ntohl(pre.id);
+    pre.cellid = ntohl(pre.cellid);
+    pre.next = ntohl(pre.next);
+    pre.nextID = ntohl(pre.nextID);
+    pre.nextName = ntohl(pre.nextName);
+    pre.owner = ntohl(pre.owner);
+    pre.creator = ntohl(pre.creator);
+    pre.ngroups = ntohl(pre.ngroups);
+    pre.nusers = ntohl(pre.nusers);
+    pre.count = ntohl(pre.count);
+    pre.instance = ntohl(pre.instance);
+    pre.owned = ntohl(pre.owned);
+    pre.nextOwned = ntohl(pre.nextOwned);
+    pre.parent = ntohl(pre.parent);
+    pre.sibling = ntohl(pre.sibling);
+    pre.child = ntohl(pre.child);
+    for (i = 0; i < PRSIZE; i++) {
+	pre.entries[i] = ntohl(pre.entries[i]);
+    }
+    if ((pre.flags & PRFREE) == 0) { /* A normal user */
+	if (cflag) (void) checkin(&pre);
+	if (((pre.flags & PRGRP) && grpflag) ||
+	    (((pre.flags & PRGRP) == 0) && !grpflag)) {
+	    if (!*didit && !cflag) {
+		*didit = 1;
+		printf("==========\n");
+	    }
+	    if (!cflag)
+		printf("Name: %s ID: %D\n", pre.name, pre.id);
+	    else display_useful_groups(&pre, fd);
+	}
+    }
+    return(nmflg ? pre.nextName : pre.nextID);
+}
+static struct contentry prco;
+void display_useful_groups(pre, fd)
+register struct prentry *pre;
+int fd;
+{
+    register int i;
+    register int offset;
+    char *id_to_name();
+    if (pre->entries[0] == 0) return;
+    printf("Group: %s\n", pre->name);
+    for (i = 0; i < PRSIZE; i++) {
+	if (pre->entries[i] == 0) break;
+	if (pre->entries[i] == PRBADID) continue;
+	printf("   Member:  %s\n", id_to_name(pre->entries[i], fd));
+    }
+    if (i == PRSIZE) {
+	offset = pre->next;
+	while (offset) {
+	    lseek(fd, offset+HDRSIZE, L_SET);
+	    read(fd, &prco, sizeof(struct contentry));
+	    prco.next = ntohl(prco.next);
+	    for (i = 0; i < COSIZE; i++) {
+		prco.entries[i] = ntohl(prco.entries[i]);
+		if (prco.entries[i] == 0) break;
+		if (prco.entries[i] == PRBADID) continue;
+		printf("   Member(co):  %s\n", id_to_name(prco.entries[i], fd));
+	    }
+	    if ((i == COSIZE) && prco.next)
+		offset = prco.next;
+	    else offset = 0;
+	}
+    }
+}
+char *id_to_name(id, fd)
+int id;
+int fd;
+{
+    register int offset;
+    struct prentry pre;
+    char *name;
+    char *check_core();
+    char *checkin();
+    long IDHash();
+    name = check_core(id);
+    if (name != NULL) return(name);
+    offset = ntohl(prh.idHash[IDHash(id)]);
+    if (offset == NULL) return("NOT FOUND");
+    while (offset) {
+	lseek(fd, offset+HDRSIZE, L_SET);
+	if (read(fd, &pre, sizeof(struct prentry)) < 0) {
+	    fprintf(stderr, "ptdump: read i/o error: %s\n",
+		    sys_errlist[errno]);
+	    exit (1);
+	}
+	pre.id = ntohl(pre.id);
+	if (pre.id == id) {
+	    name = checkin(&pre);
+	    return(name);
+	}
+	offset = ntohl(pre.nextID);
+    }
+    return("NOT FOUND");
+}
+struct hash_entry {
+    char h_name[PR_MAXNAMELEN];
+    int h_id;
+    struct hash_entry *next;
+};
+struct hash_entry *hat[HASHSIZE];
+char *checkin(pre)
+struct prentry *pre;
+{
+    struct hash_entry *he, *last;
+    register int id;
+    long IDHash();
+    id = pre->id;
+    last = (struct hash_entry *)0;
+    he = hat[IDHash(id)];
+    while (he) {
+	if (id == he->h_id) return(he->h_name);
+	last = he;
+	he = he->next;
+    }
+    he = (struct hash_entry *)malloc(sizeof(struct hash_entry));
+    if (he == NULL) {
+	fprintf(stderr, "ptdump: No Memory for internal hash table.\n");
+	exit (1);
+    }
+    he->h_id = id;
+    he->next = (struct hash_entry *)0;
+    strncpy(he->h_name, pre->name, PR_MAXNAMELEN);
+    if (last == (struct hash_entry *)0) hat[IDHash(id)] = he;
+    else last->next = he;
+    return(he->h_name);
+}
+char *check_core(id)
+register int id;
+{
+    struct hash_entry *he;
+    long IDHash();
+    he = hat[IDHash(id)];
+    while (he) {
+	if (id == he->h_id) return(he->h_name);
+	he = he->next;
+    }
+    return(NULL);
+}
+
+long IDHash(x)
+long x;
+{
+    /* returns hash bucket for x */
+    return ((abs(x)) % HASHSIZE);
+}
--- debathena-moira-4.0.0+cvs20080304.orig/afssync/ptutils.c
+++ debathena-moira-4.0.0+cvs20080304/afssync/ptutils.c
@@ -0,0 +1,1306 @@
+/*
+ * Copyright 2000, International Business Machines Corporation and others.
+ * All Rights Reserved.
+ * 
+ * This software has been released under the terms of the IBM Public
+ * License.  For details, see the LICENSE file in the top-level source
+ * directory or online at http://www.openafs.org/dl/license10.html
+ */
+
+#include <afs/param.h>
+
+#include <afs/stds.h>
+#include <sys/types.h>
+#include <stdio.h>
+#ifdef AFS_NT40_ENV 
+#include <winsock2.h>
+#else
+#include <netinet/in.h>
+#endif
+#include <string.h>
+#include <lock.h>
+#include <ubik.h>
+#include <rx/xdr.h>
+#include <afs/com_err.h>
+#include <afs/cellconfig.h>
+#include "ptserver.h"
+#include "pterror.h"
+#include <stdlib.h>
+
+/* Foreign cells are represented by the group system:authuser@cell*/
+#define AUTHUSER_GROUP "system:authuser"
+
+
+extern struct ubik_dbase *dbase;
+extern struct afsconf_dir *prdir;
+extern int pr_noAuth;
+extern int IDCmp();
+
+extern afs_int32 AddToEntry();
+static char *whoami = "ptserver";
+
+/* CorrectUserName - Check to make sure a user name is OK.  It must not include
+ *   either a colon (or it would look like a group) or an atsign (or it would
+ *   look like a foreign user).  The length is checked as well to make sure
+ *   that the user name, an atsign, and the local cell name will fit in
+ *   PR_MAXNAMELEN.  This is so this user can fit in another cells database as
+ *   a foreign user with our cell name tacked on.  This is a predicate, so it
+ *   return one if name is OK and zero if name is bogus. */
+
+static int CorrectUserName (name)
+  char *name;
+{
+    extern int pr_realmNameLen;
+
+    /* We accept foreign names, so we will deal with '@' later */
+    if (strchr (name, ':') || strchr(name, '\n')) return 0;
+    if (strlen (name) >= PR_MAXNAMELEN - pr_realmNameLen - 1) return 0; 
+    return 1;
+}
+
+/* CorrectGroupName - Like the above but handles more complicated cases caused
+ * by including the ownership in the name.  The interface works by calculating
+ * the correct name based on a given name and owner.  This allows easy use by
+ * rename, which then compares the correct name with the requested new name. */
+
+static afs_int32 CorrectGroupName (ut, aname, cid, oid, cname)
+  struct ubik_trans *ut;
+  char aname[PR_MAXNAMELEN];		/* name for group */
+  afs_int32 cid;				/* caller id */
+  afs_int32 oid;				/* owner of group */
+  char cname[PR_MAXNAMELEN];		/* correct name for group */
+{
+    afs_int32  code;
+    int   admin;
+    char *prefix;			/* ptr to group owner part */
+    char *suffix;			/* ptr to group name part */
+    char  name[PR_MAXNAMELEN];		/* correct name for group */
+    struct prentry tentry;
+
+    if (strlen (aname) >= PR_MAXNAMELEN) return PRBADNAM;
+    admin = pr_noAuth || IsAMemberOf (ut, cid, SYSADMINID);
+
+    if (oid == 0) oid = cid;
+
+    /* Determine the correct prefix for the name. */
+    if (oid == SYSADMINID) prefix = "system";
+    else {
+	afs_int32 loc = FindByID (ut, oid);
+	if (loc == 0) {
+	    /* let admin create groups owned by non-existent ids (probably
+             * setting a group to own itself).  Check that they look like
+             * groups (with a colon) or otherwise are good user names. */
+	    if (admin) {
+		strcpy (cname, aname);
+		goto done;
+	    }
+	    return PRNOENT;
+	}
+	code = pr_Read (ut, 0, loc, &tentry, sizeof(tentry));
+	if (code) return code;
+	if (ntohl(tentry.flags) & PRGRP) {
+	    if ((tentry.count == 0) && !admin) return PRGROUPEMPTY;
+	    /* terminate prefix at colon if there is one */
+	    if ((prefix = strchr(tentry.name, ':'))) *prefix = 0;
+	}
+	prefix = tentry.name;
+    }
+    /* only sysadmin allow to use 'system:' prefix */
+    if ((strcmp (prefix, "system") == 0) && !admin) return PRPERM;
+
+    strcpy (name, aname);		/* in case aname & cname are same */
+    suffix = strchr(name, ':');
+    if (suffix == 0) {
+	/* sysadmin can make groups w/o ':', but they must still look like
+         * legal user names. */
+	if (!admin) return PRBADNAM;
+	strcpy (cname, name);
+    }
+    else {
+	if (strlen(prefix)+strlen(suffix) >= PR_MAXNAMELEN) return PRBADNAM;
+	strcpy (cname, prefix);
+	strcat (cname, suffix);
+    }
+  done:
+    /* check for legal name with either group rules or user rules */
+    if ((suffix = strchr(cname, ':'))) {
+	/* check for confusing characters */
+	if (strchr(cname, '\n') ||	/* restrict so recreate can work */
+	    strchr(suffix+1, ':'))	/* avoid multiple colons */
+	    return PRBADNAM;
+    } else {
+	if (!CorrectUserName (cname)) return PRBADNAM;
+    }
+    return 0;
+}
+
+int AccessOK (ut, cid, tentry, mem, any)
+  struct ubik_trans *ut;
+  afs_int32 cid;				/* caller id */
+  struct prentry *tentry;		/* object being accessed */
+  int mem;				/* check membership in aid, if group */
+  int any;				/* if set return true */
+{   afs_int32 flags;
+    afs_int32 oid;
+    afs_int32 aid;
+
+    if (pr_noAuth) return 1;
+    if (cid == SYSADMINID) return 1;	/* special case fileserver */
+    if (tentry) {
+	flags = tentry->flags;
+	oid = tentry->owner;
+	aid = tentry->id;
+    } else {
+	flags = oid = aid = 0;
+    }
+    if (!(flags & PRACCESS)) {		/* provide default access */
+	if (flags & PRGRP)
+	    flags |= PRP_GROUP_DEFAULT;
+	else
+	    flags |= PRP_USER_DEFAULT;
+    }
+
+    if (flags & any) return 1;
+    if (oid) {
+	if ((cid == oid) ||
+	    IsAMemberOf (ut, cid, oid)) return 1;
+    }
+    if (aid > 0) {			/* checking on a user */
+	if (aid == cid) return 1;
+    } else if (aid < 0) {		/* checking on group */
+	if ((flags & mem) && IsAMemberOf (ut, cid, aid)) return 1;
+    }
+    /* Allow members of SYSVIEWERID to get membership and status only */
+    if (((mem == PRP_STATUS_MEM)||(mem == PRP_MEMBER_MEM))&&(IsAMemberOf (ut, cid, SYSVIEWERID))) return 1;
+    if (IsAMemberOf (ut, cid, SYSADMINID)) return 1;
+    return 0;				/* no access */
+}
+
+afs_int32 CreateEntry (at, aname, aid, idflag, flag, oid, creator)  
+  struct ubik_trans *at;
+  char aname[PR_MAXNAMELEN];
+  afs_int32 *aid;
+  afs_int32 idflag;
+  afs_int32 flag;
+  afs_int32 oid;
+  afs_int32 creator;
+{
+    /* get and init a new entry */
+    afs_int32 code;
+    afs_int32 newEntry;
+    struct prentry tentry, tent;
+    char *atsign;
+    
+    memset(&tentry, 0, sizeof(tentry));
+
+    if ((oid == 0) || (oid == ANONYMOUSID)) oid = creator;
+
+    if (flag & PRGRP) {
+	code = CorrectGroupName (at, aname, creator, oid, tentry.name);
+	if (code) return code;
+	if (strcmp (aname, tentry.name) != 0)  return PRBADNAM;
+    } else {				/* non-group must not have colon */
+	if (!CorrectUserName(aname)) return PRBADNAM;
+	strcpy (tentry.name, aname);
+    }
+
+    if (FindByName(at,aname, &tent)) return PREXIST;
+
+    newEntry = AllocBlock(at);
+    if (!newEntry) return PRDBFAIL;
+#ifdef PR_REMEMBER_TIMES
+    tentry.createTime = time(0);
+#endif
+
+    if (flag & PRGRP) {
+	tentry.flags = PRGRP;
+	tentry.owner = oid;
+    } else if (flag == 0) {
+        tentry.flags = 0;
+        tentry.owner = SYSADMINID;
+    } else {
+        return PRBADARG;
+    }
+
+    atsign = strchr(aname, '@');
+    if (!atsign) {
+       /* A normal user or group. Pick an id for it */
+       if (idflag) 
+	  tentry.id = *aid;
+       else {
+	  code= AllocID(at,flag,&tentry.id);
+	  if (code != PRSUCCESS) return code;
+       }
+    } else if (flag & PRGRP) {
+       /* A foreign group. Its format must be AUTHUSER_GROUP@cellname
+	* Then pick an id for the group.
+	*/
+       int badFormat;
+	    
+       *atsign = '\0';
+       badFormat = strcmp(AUTHUSER_GROUP, aname);
+       *atsign = '@';
+       if (badFormat) return PRBADNAM;
+
+       if (idflag) 
+	  tentry.id = *aid;
+       else {
+	  code= AllocID(at,flag,&tentry.id);
+	  if (code != PRSUCCESS) return code;
+       }
+    } else {
+       /* A foreign user: <name>@<cell>. The foreign user is added to
+	* its representing group. It is 
+	*/
+       char *cellGroup;
+       afs_int32 pos, n;
+       struct prentry centry;
+       extern afs_int32 allocNextId();
+
+       /* To create the user <name>@<cell> the group AUTHUSER_GROUP@<cell>
+	* must exist.
+	*/
+       cellGroup = (char *)malloc(strlen(AUTHUSER_GROUP) + strlen(atsign) + 1);
+       strcpy(cellGroup, AUTHUSER_GROUP);
+       strcat(cellGroup, atsign);
+       pos = FindByName(at, cellGroup, &centry); 
+       if (!pos) return PRBADNAM;
+       code = pr_Read (at, 0, pos, &centry, sizeof(centry));
+       if (code) return code;
+
+       /* cellid is the id of the group representing the cell */
+       tentry.cellid = ntohl(centry.id); 
+
+       if (idflag) {
+	  /* Check if id is good */
+	  if (!inRange(&centry,*aid)) return PRBADARG;
+	  tentry.id = *aid;
+       } else {
+	  /* Allocate an ID special for this foreign user. It is based 
+	   * on the representing group's id and nusers count.
+	   */
+	  tentry.id = allocNextId(&centry);
+       }
+	 
+       /* The foreign user will be added to the representing foreign
+	* group. The group can hold up to 30 entries.
+	*/
+       if (!(ntohl(centry.flags) & PRQUOTA)) {
+	  centry.flags = htonl (ntohl(centry.flags) | PRQUOTA);
+	  centry.ngroups = htonl(30);
+       }
+       n = ntohl(centry.ngroups);
+       if ( (n <= 0) && !pr_noAuth ) return PRNOMORE;
+       centry.ngroups = htonl(n - 1);
+
+       /* write updated entry for group */
+       code = pr_Write (at, 0, pos, &centry, sizeof(centry));
+
+       /* Now add the new user entry to the database */
+       tentry.creator = creator;
+       *aid = tentry.id;
+       code = pr_WriteEntry(at, 0, newEntry, &tentry);
+       if (code) return PRDBFAIL;
+       code = AddToIDHash(at, *aid, newEntry);
+       if (code != PRSUCCESS) return code;
+       code = AddToNameHash(at, aname, newEntry);
+       if (code != PRSUCCESS) return code;
+       if (inc_header_word (at, foreigncount, 1)) return PRDBFAIL;
+
+       /* Now add the entry to the authuser group for this cell.
+	* We will reread the entries for the user and the group
+	* instead of modifying them before writing them in the
+	* previous steps. Although not very efficient, much simpler
+	*/
+       pos = FindByID(at, tentry.cellid); 
+       if (!pos) return PRBADNAM;
+       code = pr_ReadEntry (at, 0, pos, &centry);
+       if (code) return code;
+       code = AddToEntry(at, &centry, pos, *aid);
+       if (code) return code;
+       /* and now the user entry */
+       pos = FindByID(at,*aid); 
+       if (!pos) return PRBADNAM;
+       code = pr_ReadEntry (at, 0, pos, &tentry);
+       if (code) return code;
+       code = AddToEntry(at, &tentry, pos, tentry.cellid);
+       if (code) return code;
+
+       return PRSUCCESS;
+    }
+
+    /* Remember the largest group id or largest user id */
+    if (flag & PRGRP) {
+	/* group ids are negative */
+	if (tentry.id < (afs_int32)ntohl(cheader.maxGroup)) {
+	    code = set_header_word (at, maxGroup, htonl(tentry.id));
+	    if (code) return PRDBFAIL;
+	}
+    }
+    else {
+	if (tentry.id > (afs_int32)ntohl(cheader.maxID)) {
+	    code = set_header_word (at, maxID, htonl(tentry.id));
+	    if (code) return PRDBFAIL;
+	}
+    }
+
+    /* Charge the creator for this group */
+    if (flag & PRGRP) {
+	afs_int32 loc = FindByID (at, creator);
+	struct prentry centry;
+	int admin;
+
+	if (loc) { /* this should only fail during initialization */
+	    code = pr_Read (at, 0, loc, &centry, sizeof(centry));
+	    if (code) return code;
+
+	    /* If quota is uninitialized, do it */
+	    if (!(ntohl(centry.flags) & PRQUOTA)) {
+	       centry.flags = htonl (ntohl(centry.flags) | PRQUOTA);
+	       centry.ngroups = centry.nusers = htonl(20);
+	    }
+
+	    /* Admins don't get charged for creating a group.
+	     * If in noAuth mode, you get changed for it but you 
+	     * are still allowed to create as many groups as you want.
+	     */
+	    admin = ( (creator == SYSADMINID) ||
+		      IsAMemberOf(at,creator,SYSADMINID) );
+	    if (!admin) {
+	       if (ntohl(centry.ngroups) <= 0) {
+		  if (!pr_noAuth) return PRNOMORE;
+		} else {
+		   centry.ngroups = htonl(ntohl(centry.ngroups)-1);
+	      }
+	    }
+
+	    code = pr_Write (at, 0, loc, &centry, sizeof(centry));
+	    if (code) return code;
+	} /* if (loc) */
+    }
+    else {
+        /* Initialize the quota for the user. Groups don't have their
+	 * quota initialized.
+	 */
+        tentry.flags |= PRQUOTA;
+	tentry.ngroups = tentry.nusers = 20;
+    }
+
+    tentry.creator = creator;
+    *aid = tentry.id;
+    code = pr_WriteEntry(at, 0, newEntry, &tentry);
+    if (code) return PRDBFAIL;
+    code = AddToIDHash(at,*aid,newEntry);
+    if (code != PRSUCCESS) return code;
+    code = AddToNameHash(at,aname,newEntry);
+    if (code != PRSUCCESS) return code;
+    if (tentry.flags & PRGRP) {
+	code = AddToOwnerChain(at,tentry.id,oid);
+	if (code) return code;
+    }
+    if (tentry.flags & PRGRP) {
+	if (inc_header_word (at, groupcount, 1)) return PRDBFAIL;
+    }
+    else if (tentry.flags & PRINST) {
+	if (inc_header_word (at, instcount, 1)) return PRDBFAIL;
+    }
+    else {
+	if (inc_header_word (at, usercount, 1)) return PRDBFAIL;
+    }
+    return PRSUCCESS;
+}
+    
+
+/* RemoveFromEntry - remove aid from bid's entries list, freeing a continuation
+ * entry if appropriate */
+
+afs_int32 RemoveFromEntry (at, aid, bid)
+  struct ubik_trans *at;
+  afs_int32 aid;
+  afs_int32 bid;
+{
+    afs_int32 code;
+    struct prentry tentry;
+    struct contentry centry;
+    struct contentry hentry;
+    afs_int32 temp;
+    afs_int32 i,j;
+    afs_int32 nptr;
+    afs_int32 hloc;
+    
+    if (aid == bid) return PRINCONSISTENT;
+    memset(&hentry, 0, sizeof(hentry));
+    temp = FindByID(at,bid);
+    if (temp == 0) return PRNOENT;
+    code = pr_ReadEntry(at, 0, temp, &tentry);
+    if (code != 0) return code;
+#ifdef PR_REMEMBER_TIMES
+    tentry.removeTime = time(0);
+#endif
+    for (i=0;i<PRSIZE;i++) {
+	if (tentry.entries[i] == aid) {  
+	    tentry.entries[i] = PRBADID;
+	    tentry.count--;
+	    code = pr_WriteEntry(at,0,temp,&tentry);
+            if (code != 0) return code;
+	    return PRSUCCESS;
+	}
+	if (tentry.entries[i] == 0)   /* found end of list */
+	    return PRNOENT;
+    }
+    hloc = 0;
+    nptr = tentry.next;
+    while (nptr != 0) {
+	code = pr_ReadCoEntry(at,0,nptr,&centry);
+	if (code != 0) return code;
+	if ((centry.id != bid) || !(centry.flags & PRCONT)) return PRDBBAD;
+	for (i=0;i<COSIZE;i++) {
+	    if (centry.entries[i] == aid) {
+		centry.entries[i] = PRBADID;
+		for (j=0;j<COSIZE;j++)
+		    if (centry.entries[j] != PRBADID &&
+			centry.entries[j] != 0) break;
+		if (j == COSIZE) {   /* can free this block */
+		    if (hloc == 0) {
+			tentry.next = centry.next;
+		    }
+		    else {
+			hentry.next = centry.next;
+			code = pr_WriteCoEntry (at, 0, hloc, &hentry);
+			if (code != 0) return code;
+		    }
+		    code = FreeBlock (at, nptr);
+		    if (code) return code;
+		}
+		else { /* can't free it yet */
+		    code = pr_WriteCoEntry(at,0,nptr,&centry);
+		    if (code != 0) return code;
+		}
+		tentry.count--;
+		code = pr_WriteEntry(at,0,temp,&tentry);
+		if (code) return PRDBFAIL;
+		return 0;
+	    }
+	    if (centry.entries[i] == 0) return PRNOENT;
+	} /* for all coentry slots */
+	hloc = nptr;
+	nptr = centry.next;
+	memcpy(&hentry, &centry, sizeof(centry));
+    } /* while there are coentries */
+    return PRNOENT;
+}
+
+/* DeleteEntry - delete the entry in tentry at loc, removing it from all
+ * groups, putting groups owned by it on orphan chain, and freeing the space */
+
+afs_int32 DeleteEntry (at, tentry, loc)
+  struct ubik_trans *at;
+  struct prentry *tentry;
+  afs_int32 loc;
+{
+    afs_int32 code;
+    struct contentry centry;
+    afs_int32  i;
+    afs_int32 nptr;
+
+    if (strchr(tentry->name,'@')) {
+       if (tentry->flags & PRGRP) {
+	/* If there are still foreign user accounts from that cell
+	   don't delete the group */
+	   if (tentry->count) return PRBADARG;
+	} else {
+	    /* adjust quota */
+
+          afs_int32 loc = FindByID (at, tentry->cellid);
+          struct prentry centry;
+          if (loc) {
+            code = pr_Read (at, 0, loc, &centry, sizeof(centry));
+            if (code) return code;
+            if (ntohl(centry.flags) & PRQUOTA) {
+		    centry.ngroups = htonl(ntohl(centry.ngroups) + 1);
+	    }
+	    code = pr_Write (at, 0, loc, &centry, sizeof(centry));
+	    if (code) return code;
+	  }
+	}
+    }
+    /* First remove the entire membership list */
+    for (i=0;i<PRSIZE;i++) {
+	if (tentry->entries[i] == PRBADID) continue;
+	if (tentry->entries[i] == 0) break;
+	code = RemoveFromEntry (at, tentry->id, tentry->entries[i]);
+	if (code) return code;
+    }
+    nptr = tentry->next;
+    while (nptr != (afs_int32)NULL) {
+	code = pr_ReadCoEntry(at,0,nptr,&centry);
+	if (code != 0) return PRDBFAIL;
+	for (i=0;i<COSIZE;i++) {
+	    if (centry.entries[i] == PRBADID) continue;
+	    if (centry.entries[i] == 0) break;
+	    code = RemoveFromEntry (at, tentry->id, centry.entries[i]);
+	    if (code) return code;
+	}
+	code = FreeBlock (at, nptr);	/* free continuation block */
+	if (code) return code;
+	nptr = centry.next;
+    }
+
+    /* Remove us from other's owned chain.  Note that this will zero our owned
+     * field (on disk) so this step must follow the above step in case we are
+     * on our own owned list. */
+    if (tentry->flags & PRGRP) {
+	if (tentry->owner) {
+	    code = RemoveFromOwnerChain (at, tentry->id, tentry->owner);
+	    if (code) return code;
+	}
+	else {
+	    code = RemoveFromOrphan (at, tentry->id);
+	    if (code) return code;
+	}
+    }
+
+    code = RemoveFromIDHash(at,tentry->id,&loc);
+    if (code != PRSUCCESS) return code;
+    code = RemoveFromNameHash(at,tentry->name,&loc);
+    if (code != PRSUCCESS) return code;
+
+    if (tentry->flags & PRGRP) {
+	afs_int32 loc = FindByID(at, tentry->creator);
+	struct prentry centry;
+	int admin;
+
+	if (loc) {
+	    code = pr_Read (at, 0, loc, &centry, sizeof(centry));
+	    if (code) return code;
+	    admin = ( (tentry->creator == SYSADMINID) ||
+		      IsAMemberOf(at,tentry->creator,SYSADMINID) );
+	    if (ntohl(centry.flags) & PRQUOTA) {
+		if (!(admin && (ntohl(centry.ngroups) >= 20))) {
+		    centry.ngroups = htonl(ntohl(centry.ngroups) + 1);
+		 }
+	    }
+	    code = pr_Write (at, 0, loc, &centry, sizeof(centry));
+	    if (code) return code;
+	}
+    }
+
+    if (tentry->flags & PRGRP) {
+        if (inc_header_word (at, groupcount, -1)) return PRDBFAIL;
+    }
+    else if (tentry->flags & PRINST) {
+	if (inc_header_word (at, instcount, -1)) return PRDBFAIL;
+    }
+    else {
+        if (strchr(tentry->name,'@')) {
+	   if (inc_header_word (at, foreigncount, -1)) return PRDBFAIL;
+	} else {
+          if (inc_header_word (at, usercount, -1)) return PRDBFAIL;
+	}
+    }
+    code = FreeBlock(at, loc);
+    return code;
+}
+
+/* AddToEntry - add aid to entry's entries list, alloc'ing a continuation block
+ * if needed.
+ *
+ * Note the entry is written out by this routine. */
+
+afs_int32 AddToEntry (tt, entry, loc, aid)
+  struct ubik_trans *tt;
+  struct prentry *entry;
+  afs_int32 loc;
+  afs_int32 aid;
+{
+    afs_int32 code;
+    afs_int32 i;
+    struct contentry nentry;
+    struct contentry aentry;
+    afs_int32 nptr;
+    afs_int32 last;				/* addr of last cont. block */
+    afs_int32 first = 0;
+    afs_int32 cloc = 0;
+    afs_int32 slot = -1;
+
+    if (entry->id == aid) return PRINCONSISTENT;
+#ifdef PR_REMEMBER_TIMES
+    entry->addTime = time(0);
+#endif
+    for (i=0;i<PRSIZE;i++) {
+	if (entry->entries[i] == aid)
+	    return PRIDEXIST;
+	if (entry->entries[i] == PRBADID) { /* remember this spot */
+	    first = 1;
+	    slot = i;
+	}
+	else if (entry->entries[i] == 0) { /* end of the line */
+	    if (slot == -1) {
+		first = 1;
+		slot = i;
+	    }
+	    break;
+	}
+    }
+    last = 0;
+    nptr = entry->next;
+    while (nptr != (afs_int32)NULL) {
+ 	code = pr_ReadCoEntry(tt,0,nptr,&nentry);
+	if (code != 0) return code;
+	last = nptr;
+	if (!(nentry.flags & PRCONT)) return PRDBFAIL;
+	for (i=0;i<COSIZE;i++) {
+	    if (nentry.entries[i] == aid)
+		return PRIDEXIST;
+	    if (nentry.entries[i] == PRBADID) {
+		if (slot == -1) {
+		    slot = i;
+		    cloc = nptr;
+		}
+	    }
+	    else if (nentry.entries[i] == 0) {
+		if (slot == -1) {
+		    slot = i;
+		    cloc = nptr;
+		}
+		break;
+	    }
+	}
+	nptr = nentry.next;
+    }
+    if (slot != -1) {			/* we found a place */
+	entry->count++;
+	if (first) {  /* place is in first block */
+	    entry->entries[slot] = aid;
+	    code = pr_WriteEntry (tt, 0, loc, entry);
+	    if (code != 0) return code;
+	    return PRSUCCESS;
+	}
+	code = pr_WriteEntry (tt, 0, loc, entry);
+	if (code) return code;
+	code = pr_ReadCoEntry(tt,0,cloc,&aentry);
+	if (code != 0) return code;
+	aentry.entries[slot] = aid;
+	code = pr_WriteCoEntry(tt,0,cloc,&aentry);
+	if (code != 0) return code;
+	return PRSUCCESS;
+    }
+    /* have to allocate a continuation block if we got here */
+    nptr = AllocBlock(tt);
+    if (last) {
+	/* then we should tack new block after last block in cont. chain */
+	nentry.next = nptr;
+	code = pr_WriteCoEntry(tt,0,last,&nentry);
+	if (code != 0) return code;
+    }
+    else {
+	entry->next = nptr;
+    }
+    memset(&aentry, 0, sizeof(aentry));
+    aentry.flags |= PRCONT;
+    aentry.id = entry->id;
+    aentry.next = 0;
+    aentry.entries[0] = aid;
+    code = pr_WriteCoEntry(tt,0,nptr,&aentry);
+    if (code != 0) return code;
+    /* don't forget to update count, here! */
+    entry->count++;
+    code = pr_WriteEntry (tt, 0, loc, entry);
+    return code;
+	
+}
+
+afs_int32 AddToPRList (alist, sizeP, id)
+  prlist *alist;
+  int *sizeP;
+  afs_int32 id;
+{
+    char *tmp;
+    int count;
+
+    if (alist->prlist_len >= *sizeP) {
+        count = alist->prlist_len + 100;
+	if (alist->prlist_val) {
+	   tmp = (char *) realloc(alist->prlist_val, count*sizeof(afs_int32));
+	} else {
+	   tmp = (char *) malloc(count*sizeof(afs_int32));
+	}
+	if (!tmp) return(PRNOMEM);
+	alist->prlist_val = (afs_int32 *)tmp;
+	*sizeP = count;
+    }
+    alist->prlist_val[alist->prlist_len++] = id;
+    return 0;
+}
+
+afs_int32 GetList (at, tentry, alist, add)
+  struct ubik_trans *at;
+  struct prentry *tentry;
+  prlist *alist;
+  afs_int32 add;
+{
+    afs_int32 code;
+    afs_int32 i;
+    struct contentry centry;
+    afs_int32 nptr;
+    int size;
+    int count = 0;
+
+    size = 0;
+    alist->prlist_val = 0;
+    alist->prlist_len = 0;
+
+    for (i=0;i<PRSIZE;i++) {
+	if (tentry->entries[i] == PRBADID) continue;
+	if (tentry->entries[i] == 0) break;
+	code = AddToPRList (alist, &size, tentry->entries[i]);
+	if (code) return code;
+    }
+
+    for (nptr = tentry->next; nptr != 0; nptr = centry.next) {
+	/* look through cont entries */
+	code = pr_ReadCoEntry(at,0,nptr,&centry);
+	if (code != 0) return code;
+	for (i=0;i<COSIZE;i++) {
+	    if (centry.entries[i] == PRBADID) continue;
+	    if (centry.entries[i] == 0) break;
+	    code = AddToPRList (alist, &size, centry.entries[i]);
+	    if (code) return code;
+	}
+	if (count++ > 50) IOMGR_Poll(), count = 0;
+    }
+
+    if (add) { /* this is for a CPS, so tack on appropriate stuff */
+	if (tentry->id != ANONYMOUSID && tentry->id != ANYUSERID) {
+	    if ((code = AddToPRList (alist, &size, ANYUSERID)) ||
+		(code = AddAuthGroup(tentry, alist, &size)) || 
+		(code = AddToPRList (alist, &size, tentry->id))) return code;
+	}
+	else {
+	    if ((code = AddToPRList (alist, &size, ANYUSERID)) ||
+		(code = AddToPRList (alist, &size, tentry->id))) return code;
+	}
+    }
+    if (alist->prlist_len > 100) IOMGR_Poll();
+    qsort(alist->prlist_val,alist->prlist_len,sizeof(afs_int32),IDCmp);
+    return PRSUCCESS;
+}
+
+
+afs_int32 GetList2 (at, tentry, tentry2 , alist, add)
+  struct ubik_trans *at;
+  struct prentry *tentry;
+  struct prentry *tentry2;
+  prlist *alist;
+  afs_int32 add;
+{
+    afs_int32 code = 0;
+    afs_int32 i;
+    struct contentry centry;
+    afs_int32 nptr;
+    afs_int32 size;
+    int count = 0;
+
+    size = 0;
+    alist->prlist_val = 0;
+    alist->prlist_len = 0;
+    for (i=0;i<PRSIZE;i++) {
+	if (tentry->entries[i] == PRBADID) continue;
+	if (tentry->entries[i] == 0) break;
+	code = AddToPRList (alist, &size, tentry->entries[i]);
+	if (code) return code;
+    }
+
+    nptr = tentry->next;
+    while (nptr != (afs_uint32)NULL) {
+	/* look through cont entries */
+	code = pr_ReadCoEntry(at,0,nptr,&centry);
+	if (code != 0) return code;
+	for (i=0;i<COSIZE;i++) {
+	    if (centry.entries[i] == PRBADID) continue;
+	    if (centry.entries[i] == 0) break;
+	    code = AddToPRList (alist, &size, centry.entries[i]);
+	    if (code) return code;
+	}
+	nptr = centry.next;
+	if (count++ > 50) IOMGR_Poll(), count = 0;
+    }
+
+    for (i=0;i<PRSIZE;i++) {
+	if (tentry2->entries[i] == PRBADID) continue;
+	if (tentry2->entries[i] == 0) break;
+	code = AddToPRList (alist, &size, tentry2->entries[i]);
+	if (code) break;
+    }
+
+    if (!code) {
+	    nptr = tentry2->next;
+	    while (nptr != (afs_uint32)NULL) {
+		/* look through cont entries */
+		code = pr_ReadCoEntry(at,0,nptr,&centry);
+		if (code != 0) break;
+		for (i=0;i<COSIZE;i++) {
+		    if (centry.entries[i] == PRBADID) continue;
+	    	    if (centry.entries[i] == 0) break;
+	    	    code = AddToPRList (alist, &size, centry.entries[i]);
+	    	    if (code) break;
+		}
+	   	nptr = centry.next;
+		if (count++ > 50) IOMGR_Poll(), count = 0;
+	    }
+    }
+    if (add) { /* this is for a CPS, so tack on appropriate stuff */
+	if (tentry->id != ANONYMOUSID && tentry->id != ANYUSERID) {
+	    if ((code = AddToPRList (alist, &size, ANYUSERID)) ||
+		(code = AddToPRList (alist, &size, AUTHUSERID)) ||
+		(code = AddToPRList (alist, &size, tentry->id))) return code;
+	}
+	else {
+	    if ((code = AddToPRList (alist, &size, ANYUSERID)) ||
+		(code = AddToPRList (alist, &size, tentry->id))) return code;
+	}
+    }
+    if (alist->prlist_len > 100) IOMGR_Poll();
+    qsort(alist->prlist_val,alist->prlist_len,sizeof(afs_int32),IDCmp);
+    return PRSUCCESS;
+}
+
+afs_int32 GetOwnedChain (ut, next, alist)
+  struct ubik_trans *ut;
+  afs_int32 *next;
+  prlist *alist;
+{   afs_int32 code;
+    struct prentry tentry;
+    int size;
+    int count = 0;
+
+    size = 0;
+    alist->prlist_val = 0;
+    alist->prlist_len = 0;
+
+    for (; *next; *next = ntohl(tentry.nextOwned)) {
+	code = pr_Read (ut, 0, *next, &tentry, sizeof(tentry));
+	if (code) return code;
+	code = AddToPRList (alist, &size, ntohl(tentry.id));
+	if (alist->prlist_len >= PR_MAXGROUPS) {
+	   return PRTOOMANY;
+	}
+	if (code) return code;
+	if (count++ > 50) IOMGR_Poll(), count = 0;
+    }
+    if (alist->prlist_len > 100) IOMGR_Poll();
+    qsort(alist->prlist_val,alist->prlist_len,sizeof(afs_int32),IDCmp);
+    return PRSUCCESS;
+}
+
+afs_int32 GetMax(at,uid,gid)
+struct ubik_trans *at;
+afs_int32 *uid;
+afs_int32 *gid;
+{
+    *uid = ntohl(cheader.maxID);
+    *gid = ntohl(cheader.maxGroup);
+    return PRSUCCESS;
+}
+
+afs_int32 SetMax(at,id,flag)
+struct ubik_trans *at;
+afs_int32 id;
+afs_int32 flag;
+{
+    afs_int32 code;
+    if (flag & PRGRP) {
+	cheader.maxGroup = htonl(id);
+	code = pr_Write(at,0,16,(char *)&cheader.maxGroup,sizeof(cheader.maxGroup));
+	if (code != 0) return code;
+    }
+    else {
+	cheader.maxID = htonl(id);
+	code = pr_Write(at,0,20,(char *)&cheader.maxID,sizeof(cheader.maxID));
+	if (code != 0) return code;
+    }
+    return PRSUCCESS;
+}
+
+afs_int32 read_DbHeader(tt)
+     struct ubik_trans *tt;
+{
+    afs_int32 code;
+
+    if (!ubik_CacheUpdate(tt)) return 0;
+
+    code = pr_Read(tt, 0, 0, (char *)&cheader, sizeof(cheader));
+    if (code != 0) {
+        com_err (whoami, code, "Couldn't read header");
+    }
+    return code;
+}
+
+int pr_noAuth;
+afs_int32 initd=0;
+
+afs_int32 Initdb()
+{
+    afs_int32 code;
+    struct ubik_trans *tt;
+    afs_int32 len;
+
+    /* init the database.  We'll try reading it, but if we're starting
+     * from scratch, we'll have to do a write transaction. */
+
+    pr_noAuth = afsconf_GetNoAuthFlag(prdir);
+
+    code = ubik_BeginTransReadAny(dbase,UBIK_READTRANS, &tt);
+    if (code) return code;
+    code = ubik_SetLock(tt,1,1,LOCKREAD);
+    if (code) {
+	ubik_AbortTrans(tt);
+	return code;
+    }
+    if (!initd) {
+	initd = 1;
+    } else if (!ubik_CacheUpdate (tt)) {
+	code = ubik_EndTrans(tt);
+	return code;
+    }
+
+    len = sizeof(cheader);
+    code = pr_Read(tt, 0, 0, (char *) &cheader, len);
+    if (code != 0) {
+	com_err (whoami, code, "couldn't read header");
+	ubik_AbortTrans(tt);
+	return code;
+    }
+    if ((ntohl(cheader.version) == PRDBVERSION) &&
+	ntohl(cheader.headerSize) == sizeof(cheader) &&
+	ntohl(cheader.eofPtr) != (afs_uint32)NULL &&
+	FindByID(tt,ANONYMOUSID) != 0){
+	/* database exists, so we don't have to build it */
+	code = ubik_EndTrans(tt);
+	if (code) return code;
+	return PRSUCCESS;
+    }
+    /* else we need to build a database */
+    code = ubik_EndTrans(tt);
+    if (code) return code;
+
+    /* Only rebuild database if the db was deleted (the header is zero) and we
+       are running noAuth. */
+    {   char *bp = (char *)&cheader;
+	int i;
+	for (i=0; i<sizeof(cheader); i++)
+	    if (bp[i])  {
+		code = PRDBBAD;
+		com_err (whoami, code,
+			 "Can't rebuild database because it is not empty");
+		return code;
+	    }
+    }
+    if (!pr_noAuth) {
+	code = PRDBBAD;
+	com_err (whoami, code,
+		 "Can't rebuild database because not running NoAuth");
+	return code;
+    }
+
+    code = ubik_BeginTrans(dbase,UBIK_WRITETRANS, &tt);
+    if (code) return code;
+
+    code = ubik_SetLock(tt,1,1,LOCKWRITE);
+    if (code) {
+	ubik_AbortTrans(tt);
+	return code;
+    }
+
+    /* before doing a rebuild, check again that the dbase looks bad, because
+     * the previous check was only under a ReadAny transaction, and there could
+     * actually have been a good database out there.  Now that we have a
+     * real write transaction, make sure things are still bad.
+     */
+    if ((ntohl(cheader.version) == PRDBVERSION) &&
+	ntohl(cheader.headerSize) == sizeof(cheader) &&
+	ntohl(cheader.eofPtr) != (afs_uint32)NULL &&
+	FindByID(tt,ANONYMOUSID) != 0){
+	/* database exists, so we don't have to build it */
+	code = ubik_EndTrans(tt);
+	if (code) return code;
+	return PRSUCCESS;
+    }
+
+    /* Initialize the database header */
+    if ((code = set_header_word (tt, version, htonl(PRDBVERSION))) ||
+	(code = set_header_word (tt, headerSize, htonl(sizeof(cheader)))) ||
+	(code = set_header_word (tt, eofPtr, cheader.headerSize))) {
+	com_err (whoami, code, "couldn't write header words");
+	ubik_AbortTrans(tt);
+	return code;
+    }
+
+#define InitialGroup(id,name) do {    \
+    afs_int32 temp = (id);		      \
+    afs_int32 flag = (id) < 0 ? PRGRP : 0; \
+    code = CreateEntry		      \
+	(tt, (name), &temp, /*idflag*/1, flag, SYSADMINID, SYSADMINID); \
+    if (code) {			      \
+	com_err (whoami, code, "couldn't create %s with id %di.", 	\
+		 (name), (id));	      \
+	ubik_AbortTrans(tt);	      \
+	return code;		      \
+    }				      \
+} while (0)
+
+    InitialGroup (SYSADMINID, "system:administrators");
+    InitialGroup (SYSBACKUPID, "system:backup");
+    InitialGroup (ANYUSERID, "system:anyuser");
+    InitialGroup (AUTHUSERID, "system:authuser");
+    InitialGroup (SYSVIEWERID, "system:ptsviewers");
+    InitialGroup (ANONYMOUSID, "anonymous");
+
+    /* Well, we don't really want the max id set to anonymousid, so we'll set
+     * it back to 0 */
+    code = set_header_word (tt, maxID, 0); /* correct in any byte order */
+    if (code) {
+	com_err (whoami, code, "couldn't reset max id");
+	ubik_AbortTrans(tt);
+	return code;
+    }
+
+    code = ubik_EndTrans(tt);
+    if (code) return code;
+    return PRSUCCESS;
+}
+
+afs_int32 ChangeEntry (at, aid, cid, name, oid, newid)
+  struct ubik_trans *at;
+  afs_int32 aid;
+  afs_int32 cid;
+  char *name;
+  afs_int32 oid;
+  afs_int32 newid;
+{
+    afs_int32 code;
+    afs_int32 i, nptr, pos;
+    struct contentry centry;
+    struct prentry tentry, tent;
+    afs_int32 loc;
+    afs_int32 oldowner;
+    char holder[PR_MAXNAMELEN];
+    char temp[PR_MAXNAMELEN];
+    char oldname[PR_MAXNAMELEN];
+    char *atsign;
+
+    memset(holder, 0, PR_MAXNAMELEN);
+    memset(temp, 0, PR_MAXNAMELEN);
+    loc = FindByID(at,aid);
+    if (!loc) return PRNOENT;
+    code = pr_ReadEntry(at,0,loc,&tentry);
+    if (code) return PRDBFAIL;
+    if (tentry.owner != cid &&
+	!IsAMemberOf(at,cid,SYSADMINID) &&
+	!IsAMemberOf(at,cid,tentry.owner) &&
+	!pr_noAuth) return PRPERM;
+#ifdef PR_REMEMBER_TIMES
+    tentry.changeTime = time(0);
+#endif
+
+    /* we're actually trying to change the id */
+    if (newid && (newid != aid)) {
+	if (!IsAMemberOf(at,cid,SYSADMINID) && !pr_noAuth) return PRPERM;
+
+	pos = FindByID(at,newid);
+	if (pos) return PRIDEXIST;  /* new id already in use! */
+	if ((aid < 0 && newid > 0) || (aid > 0 && newid < 0)) return PRPERM;
+
+	/* Should check that foreign users id to change to is good: inRange() */
+
+	/* if new id is not in use, rehash things */
+	code = RemoveFromIDHash(at,aid,&loc);
+	if (code != PRSUCCESS) return code;
+	tentry.id = newid;
+	code = pr_WriteEntry(at,0,loc,&tentry);
+	if (code) return code;
+	code = AddToIDHash(at,tentry.id,loc);
+	if (code) return code;
+
+	/* get current data */
+	code = pr_ReadEntry(at, 0, loc, &tentry);
+	if (code) return PRDBFAIL;
+
+	/* Also change the references from the membership list */
+	for (i=0; i<PRSIZE; i++) {
+	   if (tentry.entries[i] == PRBADID) continue;
+	   if (tentry.entries[i] == 0) break;
+           pos = FindByID(at, tentry.entries[i]);
+	   if (!pos) return(PRDBFAIL);
+	   code = RemoveFromEntry(at, aid, tentry.entries[i]);
+	   if (code) return code;
+	   code = pr_ReadEntry(at, 0, pos, &tent);
+	   if (code) return code;
+	   code = AddToEntry(at, &tent, pos, newid);
+	   if (code) return code;
+	}
+	/* Look through cont entries too. This needs to be broken into
+	 * seperate transaction so that no one transaction becomes too 
+	 * large to complete.
+	 */
+	for (nptr=tentry.next; nptr; nptr=centry.next) {
+	   code = pr_ReadCoEntry(at, 0, nptr, &centry);
+           if (code) return code;
+           for (i=0; i<COSIZE; i++) {
+	      if (centry.entries[i] == PRBADID) continue;
+	      if (centry.entries[i] == 0) break;
+	      pos = FindByID(at, centry.entries[i]);
+	      if (!pos) return(PRDBFAIL);
+	      code = RemoveFromEntry(at, aid, centry.entries[i]);
+	      if (code) return code;
+	      code = pr_ReadEntry(at, 0, pos, &tent);
+	      if (code) return code;
+	      code = AddToEntry(at, &tent, pos, newid);
+	      if (code) return code;
+	   }
+       }
+    }
+
+    atsign = strchr(tentry.name, '@'); /* check for foreign entry */
+
+    /* Change the owner */
+    if (oid && (oid != tentry.owner)) {
+	/* only groups can have their owner's changed */
+	if (!(tentry.flags & PRGRP)) return PRPERM;
+	if (atsign != NULL) return PRPERM;
+	oldowner = tentry.owner;
+	tentry.owner = oid;
+	/* The entry must be written through first so Remove and Add routines
+         * can operate on disk data */
+	code = pr_WriteEntry(at,0,loc,(char *)&tentry);
+	if (code) return PRDBFAIL;
+
+	/* switch owner chains */
+	if (oldowner)		/* if it has an owner */
+	   code = RemoveFromOwnerChain(at,tentry.id,oldowner);
+	else			/* must be an orphan */
+	   code = RemoveFromOrphan(at,tentry.id);
+	if (code) return code;
+	code = AddToOwnerChain(at,tentry.id,tentry.owner);
+	if (code) return code;
+
+	/* fix up the name */
+	if (strlen(name) == 0) name = tentry.name;
+	/* get current data */
+	code = pr_ReadEntry(at,0,loc,&tentry);
+	if (code) return PRDBFAIL;
+    }
+
+    /* Change the name, if name is a ptr to tentry.name then this name change
+     * is due to a chown, otherwise caller has specified a new name */
+    if ((name == tentry.name) ||
+	(*name && (strcmp (tentry.name, name) != 0))) {
+	strncpy (oldname, tentry.name, PR_MAXNAMELEN);
+	if (tentry.flags & PRGRP) {
+   	    /* don't let foreign cell groups change name */
+  	    if (atsign != NULL) return PRPERM;
+	    code = CorrectGroupName (at, name, cid, tentry.owner, tentry.name);
+	    if (code) return code;
+
+	    if (name == tentry.name) {	/* owner fixup */
+		if (strcmp (oldname, tentry.name) == 0) goto nameOK;
+	    } else {			/* new name, caller must be correct */
+		if (strcmp (name, tentry.name) != 0) return PRBADNAM;
+	    }
+	}
+	else
+	/* Allow a foreign name change only if the cellname part is
+	   the same */
+	{
+            char *newatsign;
+
+	    newatsign = strchr(name, '@');
+	    if (newatsign != atsign){ /* if they are the same no problem*/
+	       /*if the pointers are not equal the strings better be */
+	       if ((atsign == NULL) || (newatsign == NULL) ||
+		    strcmp (atsign,newatsign)) return PRPERM;
+	    } 
+	    if (!CorrectUserName(name)) return PRBADNAM;
+	}
+
+	pos = FindByName(at,name, &tent);
+	if (pos) return PREXIST;
+	code = RemoveFromNameHash (at, oldname, &loc);
+	if (code != PRSUCCESS) return code;
+	strncpy (tentry.name, name, PR_MAXNAMELEN);
+	code = pr_WriteEntry(at,0,loc,(char *)&tentry);
+	if (code) return PRDBFAIL;
+	code = AddToNameHash(at,tentry.name,loc);
+	if (code != PRSUCCESS) return code;
+nameOK:;
+    }
+    return PRSUCCESS;
+}
+
+
+afs_int32 allocNextId(cellEntry)
+     struct prentry *cellEntry;
+{
+	/* Id's for foreign cell entries are constructed as follows:
+	   The 16 low order bits are the group id of the cell and the
+	   top 16 bits identify the particular users in that cell */
+
+	afs_int32 id;
+
+
+	id = (ntohl(cellEntry -> nusers) +1); 
+	cellEntry->nusers = htonl(id);
+				      /* use the field nusers to keep 
+					 the next available id in that
+					 foreign cell's group. Note :
+					 It would seem more appropriate
+					 to use ngroup for that and nusers
+					 to enforce the quota, however pts
+					 does not have an option to change 
+					 foreign users quota yet  */
+
+	id = (id << 16) | ((ntohl(cellEntry-> id)) & 0x0000ffff);
+	return id;
+}
+
+int inRange(cellEntry,aid)
+struct prentry *cellEntry;
+afs_int32 aid;
+{
+	afs_uint32 id,cellid,groupid;
+
+
+	/*
+	  The only thing that we want to make sure here is that
+	  the id is in the legal range of this group. If it is
+	  a duplicate we don't care since it will get caught 
+	  in a different check.
+	*/
+
+	cellid = aid & 0x0000ffff;
+	groupid =  (ntohl(cellEntry-> id)) & 0x0000ffff;
+	if (cellid != groupid) return 0; /* not in range */
+
+	/* 
+	   if we got here we're ok but we need to update the nusers
+	   field in order to get the id correct the next time that 
+	   we try to allocate it automatically
+	*/
+
+	id = aid >> 16;
+	if (id > ntohl(cellEntry -> nusers))
+		cellEntry -> nusers = htonl(id);
+	return 1;
+
+}
+
+AddAuthGroup(tentry, alist, size)
+  struct prentry *tentry;
+  prlist *alist;
+  afs_int32 *size;
+{
+	if (!(strchr(tentry->name, '@'))) 
+             return (AddToPRList (alist, size, AUTHUSERID));
+	else 
+	     return PRSUCCESS;
+}
--- debathena-moira-4.0.0+cvs20080304.orig/afssync/script.pl
+++ debathena-moira-4.0.0+cvs20080304/afssync/script.pl
@@ -0,0 +1,239 @@
+#!/moira/bin/perl
+
+$host = "maeander";
+$ptdump = "/var/local/ptdump";
+$skip_to_members = 0;
+
+# make sure process is unlimited
+`csh -fc 'limit datasize'` =~ /datasize\s*(\w*) kbytes/;
+if ($1 < 10000) {
+    die "Must 'unlimit' before running this script!\n";
+}
+
+&startquel;
+&quelcmd("set autocommit on");
+
+if (!$skip_to_members) {
+ptdumpagain:
+open(AUSERS, "rsh $host $ptdump 2>&1 |") || die "Couldn't get to $host\n";
+
+while (<AUSERS>) {
+    if (/Ubik Version number changed during execution/) {
+	close AUSERS;
+	undef %AUSERS;
+	print "AFS database changed, trying again.\n";
+	goto ptdumpagain;
+    }
+    if (/Name: (\w*) ID: (\d*)/ && $2<32767) {
+	$AUSERS{$1} = $2;
+    }
+}
+
+close(AUSERS);
+print "Got the users from AFS\n";
+
+$AUSERS{"nobody"} = 32767;
+delete $AUSERS{"anonymous"};
+#$AUSERS{"CLU"} = 60;
+#delete $AUSERS{"clu"};
+#$AUSERS{"Saltzer"} = 994;
+#delete $AUSERS{"saltzer"};
+
+@VAL = &quelcmd("select login, uid from users where status=1 or status=2");
+printf("Got %d users from Moira\n", scalar(@VAL));
+
+open(OUT, ">user.add") || die "Couldn't open output file\n";
+
+while ($_ = shift @VAL) {
+    tr/A-Z/a-z/;
+    if ($_ =~ /\|(\w*)\s*\|\s*(\d*)\|/) {
+	if ($AUSERS{$1} == $2) {
+	    delete $AUSERS{$1};
+	} else {
+	    print OUT "/moira/bin/pts createuser -name $1 -id $2\n";
+	}
+    }
+}
+
+close OUT;
+open(OUT, ">user.del") || die "Couldn't open output file\n";
+
+foreach $login (keys %AUSERS) {
+    print OUT "/moira/bin/pts delete $login\n";
+}
+
+close OUT;
+undef @VAL;
+undef %AUSERS;
+print "Done processing users\n";
+
+groupagain:
+open(AGROUP, "rsh $host $ptdump -g 2>&1 |") || die "Couldn't get to $host\n";
+
+while (<AGROUP>) {
+    if (/Ubik Version number changed during execution/) {
+	close AGROUP;
+	undef %AGROUP;
+	print "AFS database changed, trying again.\n";
+	goto groupagain;
+    }
+    if (/Name: system:(\w*) ID: -(\d*)/ && $2<32767) {
+	$AGROUP{$1} = $2;
+    }
+}
+
+close(AGROUP);
+print "Got the groups from AFS\n";
+
+$AGROUP{"mit"} = 101;
+delete $AGROUP{"anyuser"};
+#$AGROUP{"CLU"} = 184;
+#delete $AGROUP{"clu"};
+#$AGROUP{"Saltzer"} = 185;
+#delete $AGROUP{"saltzer"};
+
+@VAL = &quelcmd("select name, gid from list where active=1 and grouplist=1");
+printf("Got %d groups from Moira\n", scalar(@VAL));
+open(OUT, ">group.add") || die "Couldn't open output file\n";
+
+while ($_ = shift @VAL) {
+    tr/A-Z/a-z/;
+    if ($_ =~ /\|(\w*)\s*\|\s*(\d*)\|/) {
+	if ($AGROUP{$1} == $2) {
+	    delete $AGROUP{$1};
+	} else {
+	    print OUT "/moira/bin/pts creategroup -name system:$1 -owner system:administrators -id -$2\n";
+	}
+    }
+}
+
+close OUT;
+open(OUT, ">group.del") || die "Couldn't open output file\n";
+
+foreach $group (keys %AGROUP) {
+    print OUT "/moira/bin/pts delete system:$group\n";
+}
+close OUT;
+
+undef @VAL;
+undef %AGROUP;
+print "Done processing groups\n";
+}
+
+memberagain:
+open(AMEM, "rsh $host $ptdump -g -c 2>&1 |") || die "Couldn't get to $host\n";
+
+while (<AMEM>) {
+    if (/Ubik Version number changed during execution/) {
+	close AMEM;
+	undef @AMEM;
+	print "AFS database changed, trying again.\n";
+	goto memberagain;
+    }
+    if (/Group: system:([^\s]*)/) {
+	$list = $1;
+    } elsif (/Group: /) {
+	$list = "";
+    } elsif (/Member:  ([^\s.]*)$/) {
+	if ($list) {
+	    push(@AMEM, $list . " " . $1);
+	}
+    } elsif (/Member\(co\):  ([^\s.]*)$/) {
+	if ($list) {
+	    push(@AMEM, $list . " " . $1);
+	}
+    }
+}
+
+close(AMEM);
+printf("Got %d members from AFS\n", scalar(@AMEM));
+
+@VAL = &quelcmd("select l.name, u.login from list l, users u, imembers m where l.list_id=m.list_id and u.users_id=m.member_id and m.member_type='USER' and l.grouplist=1 and l.active=1 and (u.status=1 or u.status=2)");
+printf("Got %d members from Moira\n", scalar(@VAL));
+
+while ($_ = shift @VAL) {
+    tr/A-Z/a-z/;
+    if ($_ =~ /\|([^\s\|]*)\s*\|([^\s\|]*)\s*\|/) {
+	push(@MMEM, $1 . " " . $2);
+    }
+}
+
+#  throw away column headings
+pop @MMEM;
+undef @VAL;
+@AMEM1 = sort @AMEM;
+@MMEM1 = sort @MMEM;
+
+open(OUT, ">member.del") || die "Couldn't open output file\n";
+open(OUT1, ">member.add") || die "Couldn't open output file\n";
+
+while ($#AMEM1 + $#MMEM1 > 0) {
+    if ($AMEM1[0] eq $MMEM1[0]) {
+	shift @AMEM1;
+	shift @MMEM1;
+    } elsif ($AMEM1[0] lt $MMEM1[0] && $#AMEM1 > 0) {
+	($list, $user) = split(/ /, shift @AMEM1);
+	print OUT "/moira/bin/pts removeuser -user $user -group system:$list\n";
+    } elsif ($MMEM1[0] lt $AMEM1[0] && $#MMEM1 > 0) {
+	($list, $user) = split(/ /, shift @MMEM1);
+	if (($user eq "login" && $list eq "name") || $user eq "root") {
+	    next;
+	}
+	print OUT1 "/moira/bin/pts adduser -user $user -group system:$list\n";
+    } else {
+	last;
+    }
+}
+
+close OUT;
+close OUT1;
+
+print "Done processing members.\n";
+
+system("cat member.del group.del user.del user.add group.add member.add > fixit");
+
+&stopquel;
+exit 0;
+
+
+sub startquel {
+	$SIG{'INT'} = $SIG{'TERM'} = $SIG{'HUP'} = 'handler';
+	$ENV{"TERM"} = "glass";
+	pipe(CREAD, QUELIN);
+	pipe(QUELOUT, COUT);
+	select(QUELIN), $|=1;
+	select(STDOUT);
+	$quelpid = fork;
+	if (! $quelpid) {
+	    select(COUT), $|=1;
+	    open(STDOUT, ">&COUT");
+	    open(STDERR, ">/dev/null");
+	    open(STDIN, "<&CREAD");
+	    exec "sql moira";
+	    exit(1);
+	}
+	close(CREAD);
+	close(COUT);
+}
+
+sub quelcmd {
+	local (@RETVAL);
+	print QUELIN $_[0], "\\g\n";
+	while (($_ = <QUELOUT>) !~ /Executing \. \. \./) { next; }
+	while (($_ = <QUELOUT>) !~ /^continue$/) { push(@RETVAL, $_); }
+	return @RETVAL;
+}
+
+sub stopquel {
+	print QUELIN "\\q\n";
+	close QUELIN;
+	close QUELOUT;
+}
+
+sub  handler {
+	local($sig) = @_;
+	&stopquel;
+	kill "HUP", $quelpid;
+	print("Caught a signal $sig\n");
+	exit(1);
+}
--- debathena-moira-4.0.0+cvs20080304.orig/afssync/sync.pc
+++ debathena-moira-4.0.0+cvs20080304/afssync/sync.pc
@@ -0,0 +1,309 @@
+/* $Header: /afs/athena.mit.edu/astaff/project/moiradev/repository/moira/afssync/sync.pc,v 1.7 2007-05-16 19:42:00 zacheiss Exp $
+ *
+ *
+ *  (c) Copyright 1989 by the Massachusetts Institute of Technology.
+ *  For copying and distribution information, please see the file
+ *  <mit-copyright.h>.
+ */
+
+#include <mit-copyright.h>
+#include <stdio.h>
+#include <sys/file.h>
+#include <string.h>
+
+#include <rx/xdr.h>
+#include "ptint.h"
+#include "ptserver.h"
+#include "pterror.h"
+
+#include <moira.h>
+#include <moira_site.h>
+#include <ctype.h>
+
+EXEC SQL INCLUDE sqlca;
+
+EXEC SQL BEGIN DECLARE SECTION;
+char db[33] = "moira";
+EXEC SQL END DECLARE SECTION;
+
+void do_passwd(void);
+void do_groups(void);
+void sqlerr(void);
+
+#ifndef min
+#define min(x,y)	((x) < (y) ? (x) : (y))
+#endif
+char *whoami = "sync";
+
+int dbase_fd;
+
+int ucount = 0;
+int gcount = 0;
+int kcount = 0;
+int mcount = 0;
+
+struct hash *users;
+struct hash *groups;
+
+struct member {
+    struct entry *user;
+    struct entry *group;
+    struct member *unext;
+    struct member *gnext;
+};
+struct entry {
+    long id;
+    struct member *members;
+};
+
+int main(int argc, char **argv)
+{
+    int status;
+    long t;
+
+    setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
+
+    if (argc > 2 && !strcmp(argv[1], "-db")) {
+	strncpy(db, argv[2], sizeof(db)-1);
+	argc -= 2;
+	argv += 2;
+    }
+    if (argc != 2) {
+	fprintf(stderr, "usage: %s [-db moira] outfile\n", whoami);
+	exit(MR_ARGS);
+    }
+
+    dbase_fd = open(argv[1], O_RDWR|O_CREAT|O_TRUNC, 0660);
+    if (dbase_fd < 0) {
+	perror("opening data file");
+	exit(1);
+    }
+
+    initialize_sms_error_table();
+    initialize_pt_error_table();
+    Initdb();					/* Initialize prdb */
+    
+    users = create_hash(10000);
+    groups = create_hash(15000);
+
+    EXEC SQL WHENEVER SQLERROR DO sqlerr();
+    EXEC SQL CONNECT :db IDENTIFIED BY :db;
+
+    do_passwd();
+    do_groups();
+
+    t = time(0);
+    fprintf(stderr, "Done (%d users, %d groups, %d kerberos, %d members): %s",
+	    ucount, gcount, kcount, mcount, ctime(&t));
+
+    EXEC SQL COMMIT;
+
+    exit(MR_SUCCESS);
+}
+
+
+void do_passwd(void)
+{
+    EXEC SQL BEGIN DECLARE SECTION;
+    char login[9], name[33];
+    int uid, id, status;
+    EXEC SQL END DECLARE SECTION;
+
+    long t;
+    struct prentry tentry;
+    struct entry *u;
+
+    t = time(0);
+    fprintf(stderr, "Doing users: %s", ctime(&t));
+
+    EXEC SQL DECLARE u_cursor CURSOR FOR
+	SELECT u.login, u.unix_uid, u.users_id
+	FROM users u
+	WHERE u.unix_uid > 0 AND (u.status = 1 OR u.status = 2)
+	ORDER BY unix_uid;
+    EXEC SQL OPEN u_cursor;
+    while (1) {
+	EXEC SQL FETCH u_cursor INTO :login, :uid, :id;
+	if (sqlca.sqlcode != 0) break;
+	
+	lowercase(strtrim(login));
+
+	if (FindByID(0,uid))
+	    status = PRIDEXIST;
+	else
+	    status = CreateEntry(0,login,&uid,1	/*idflag*/,0/*gflag*/,
+				 SYSADMINID	/*oid*/, SYSADMINID/*cid*/);
+	if (status)
+	    fprintf(stderr, "Error adding user %s uid %d: %s\n",
+		    login, uid, error_message(status));
+	else {
+	    u = (struct entry *)malloc(sizeof(struct entry));
+	    u->id = uid;
+	    u->members = 0;
+	    hash_store(users, id, u);
+	    ucount++;
+	}
+    }
+    EXEC SQL CLOSE u_cursor;
+    return;
+}
+
+
+
+void do_groups(void)
+{
+    EXEC SQL BEGIN DECLARE SECTION;
+    char name[33], string[129];
+    int gid, id, lid, hide, ustatus;
+    EXEC SQL END DECLARE SECTION;
+
+    long status, pos;
+    struct prentry gentry, uentry;
+    struct entry *u, *g;
+    struct member *m;
+    struct bucket **p, *b;
+    char namebuf[40];
+    long aid, t;
+
+    t = time(0);
+    fprintf(stderr, "Doing groups: %s", ctime(&t));
+
+    EXEC SQL DECLARE l_cursor CURSOR FOR
+	SELECT l.name, l.gid, l.list_id, l.hidden
+	FROM list l
+	WHERE l.gid > 0 AND l.active != 0 AND l.grouplist != 0
+	ORDER BY gid;
+    EXEC SQL OPEN l_cursor;
+    while (1) {
+	EXEC SQL FETCH l_cursor INTO :name, :gid, :lid, :hide;
+	if (sqlca.sqlcode != 0) break;
+	
+	lowercase(strtrim(name));
+	sprintf(namebuf, "system:%s", name);
+	aid = -gid;
+
+	if (FindByID(0, aid))
+	    status = PRIDEXIST;
+	else
+	    status = CreateEntry(0,namebuf,&aid,1 /*idflag*/,PRGRP/*gflag*/,
+				 SYSADMINID	/*oid*/, SYSADMINID/*cid*/);
+	if (status)
+	    fprintf(stderr, "Error adding group %s id %d: %s\n",
+		    namebuf, aid, error_message(status));
+
+	if ((status==0 || status==PRIDEXIST) &&
+	    (aid!=ANYUSERID && aid!=AUTHUSERID)) {
+
+	    g = (struct entry *)malloc(sizeof(struct entry));
+	    g->id = aid;
+	    g->members = 0;
+	    hash_store(groups, lid, g);
+	    gcount++;
+
+	    /* Set modes on hidden lists (S----) */
+	    if (hide) {
+		pos = FindByID(0, aid);
+		status = pr_Read(0, 0, pos, &gentry, sizeof(gentry));
+		if (!status) {
+		    gentry.flags = htonl(PRGRP|PRACCESS|PRP_STATUS_ANY);
+		    status = pr_Write(0, 0, pos, &gentry, sizeof(gentry));
+		}
+		if (status)
+		    fprintf(stderr,
+			    "Error setting flags on group %s: %s\n",
+			    namebuf, error_message(status));
+	    }
+	}
+    }
+    EXEC SQL CLOSE l_cursor;
+
+    t = time(0);
+    fprintf(stderr, "Reading/preparing members: %s", ctime(&t));
+
+    EXEC SQL DECLARE m_cursor CURSOR FOR
+	SELECT m.list_id, m.member_id, m.member_type
+	FROM imembers m
+	ORDER BY member_id;
+    EXEC SQL OPEN m_cursor;
+    while (1) {
+	EXEC SQL FETCH m_cursor INTO :lid, :id, :name;
+	if (sqlca.sqlcode != 0) break;
+
+	if (!(g = (struct entry *)hash_lookup(groups, lid)))
+	    continue;
+
+	strtrim(name);
+	if (!strcmp(name, "USER")) {
+	    if (u = (struct entry *)hash_lookup(users, id)) {
+		m = (struct member *)malloc(sizeof(struct member));
+		m->user = u;
+		m->group = g;
+		m->unext = u->members;
+		m->gnext = g->members;
+		u->members = g->members = m;
+		mcount++;
+	    }
+	}
+    }
+    EXEC SQL CLOSE m_cursor;
+
+    t = time(0);
+    fprintf(stderr, "Doing members: %s", ctime(&t));
+
+    /* Do the bulk of the membership quickly.
+     * Add PRSIZE members into the user/group record.  After that, we
+     * require the use of continuation records, but we assume this is
+     * few enough that we do this the slow way (AddToEntry).
+     */
+    for (p = &(users->data[users->size - 1]); p >= users->data; p--) {
+	for (b = *p; b; b = b->next) {
+	    if ((u = (struct entry *)b->data)->members == 0)
+		continue;
+	    pos = FindByID(0, u->id);
+	    pr_Read(0, 0, pos, &uentry, sizeof(uentry));
+	    for (t=0, m=u->members; m && t<PRSIZE; m=m->unext, t++)
+		uentry.entries[t] = htonl(m->group->id);
+	    uentry.count = htonl(t);
+	    pr_Write(0, 0, pos, &uentry, sizeof(uentry));
+	    if (m) {
+		pr_ReadEntry(0, 0, pos, &uentry);
+		while (m) {
+		    AddToEntry(0, &uentry, pos, m->group->id);
+		    m = m->unext;
+		}
+	    }
+	}
+    }
+    for (p = &(groups->data[groups->size - 1]); p >= groups->data; p--) {
+	for (b = *p; b; b = b->next) {
+	    if ((g = (struct entry *)b->data)->members == 0)
+		continue;
+	    pos = FindByID(0, g->id);
+	    pr_Read(0, 0, pos, &gentry, sizeof(gentry));
+	    for (t=0, m=g->members; m && t<PRSIZE; m=m->gnext, t++)
+		gentry.entries[t] = htonl(m->user->id);
+	    gentry.count = htonl(t);
+	    pr_Write(0, 0, pos, &gentry, sizeof(gentry));
+	    if (m) {
+		pr_ReadEntry(0, 0, pos, &gentry);
+		while (m) {
+		    AddToEntry(0, &gentry, pos, m->user->id);
+		    m = m->gnext;
+		}
+	    }
+	}
+    }
+    return;
+}
+
+    
+void sqlerr(void)
+{
+    char buf[256];
+    int size=256, len=0;
+
+    sqlglm(buf, &size, &len);
+    buf[len]='\0';
+    com_err(whoami, MR_DBMS_ERR, " code %d\n%s", sqlca.sqlcode, buf);
+    exit(MR_DBMS_ERR);
+}
--- debathena-moira-4.0.0+cvs20080304.orig/afssync/ubik.c
+++ debathena-moira-4.0.0+cvs20080304/afssync/ubik.c
@@ -0,0 +1,173 @@
+/* $Id: ubik.c,v 1.6 2006-05-12 20:20:08 zacheiss Exp $ */
+
+#include <sys/types.h>
+#include <netinet/in.h>
+
+#include <lock.h>
+#define UBIK_INTERNALS
+#include <stds.h>
+#include <rx/xdr.h>
+#include "print.h"
+#include "prserver.h"
+
+/* Stolen bits of ubik.h. */
+
+struct ubik_version {
+  afs_int32 epoch;
+  afs_int32 counter;
+};
+typedef struct ubik_version ubik_version;
+
+/* ubik header file structure */
+struct ubik_hdr {
+  afs_int32 magic;            /* magic number */
+  short pad1;                 /* some 0-initd padding */
+  short size;                 /* header allocation size */
+  struct ubik_version version;        /* the version for this file */
+};
+
+#define HDRSIZE             64  /* bytes of header per dbfile */
+#define UBIK_MAGIC      0x354545
+
+extern int dbase_fd;
+struct ubik_dbase *dbase;
+
+int ubik_ServerInit()
+{
+    return(0);
+}
+
+int ubik_BeginTrans()
+{
+    static int init=0;
+    struct ubik_hdr thdr;
+
+    if (!init) {
+	thdr.version.epoch = htonl(0);
+	thdr.version.counter = htonl(0);
+	thdr.magic = htonl(UBIK_MAGIC);
+	thdr.size = htonl(HDRSIZE);
+	lseek(dbase_fd, 0, 0);
+	write(dbase_fd, &thdr, sizeof(thdr));
+	fsync(dbase_fd);
+	init = 1;
+    }
+    return(0);
+}
+
+int ubik_BeginTransReadAny()
+{
+    return(0);
+}
+
+int ubik_AbortTrans()
+{
+    return(0);
+}
+
+int ubik_EndTrans()
+{
+    return(0);
+}
+
+int ubik_Tell()
+{
+    return(0);
+}
+
+int ubik_Truncate()
+{
+    return(0);
+}
+
+long ubik_SetLock()
+{
+    return(0);
+}
+
+int ubik_WaitVersion()
+{
+    return(0);
+}
+
+int ubik_CacheUpdate()
+{
+    return(0);
+}
+
+int panic(a, b, c, d)
+char *a, *b, *c, *d;
+{
+    printf(a, b, c, d);
+    abort();
+    printf("BACK FROM ABORT\n");    /* shouldn't come back from floating pt exception */
+    exit(1);    /* never know, though */
+}
+
+int ubik_GetVersion(dummy, ver)
+int dummy;
+struct ubik_version *ver;
+{
+    memset(ver, 0, sizeof(struct ubik_version));
+    return(0);
+}
+
+
+int ubik_Seek(tt, afd, pos)
+struct ubik_trans *tt;
+long afd;
+long pos;
+{
+    if (lseek(dbase_fd, pos+HDRSIZE, 0) < 0) {
+	perror("ubik_Seek");
+	return(-1);
+    }
+    return(0);
+}
+
+int ubik_Write(tt, buf, len)
+struct ubik_trans *tt;
+char *buf;
+long len;
+{
+    int status;
+
+    status = write(dbase_fd, buf, len);
+    if (status < len) {
+	perror("ubik_Write");
+	return(1);
+    }
+    return(0);
+}
+
+int ubik_Read(tt, buf, len)
+struct ubik_trans *tt;
+char *buf;
+long len;
+{
+    int status;
+    
+    status = read(dbase_fd, buf, len);
+    if (status < 0) {
+	perror("ubik_Read");
+	return(1);
+    }
+    if (status < len)
+      memset(&buf[status], 0, len - status);
+    return(0);
+}
+
+struct rx_securityClass *ubik_sc[3];
+
+/* Other declarations */
+
+afsconf_GetNoAuthFlag()
+{
+    return(1);
+}
+
+
+char *prdir = "/dev/null";
+struct prheader cheader;
+int pr_realmNameLen;
+char *pr_realmName;
--- debathena-moira-4.0.0+cvs20080304.orig/afssync/utils.c
+++ debathena-moira-4.0.0+cvs20080304/afssync/utils.c
@@ -0,0 +1,797 @@
+/* Copyright (C) 1989 Transarc Corporation - All rights reserved */
+/*
+ * P_R_P_Q_# (C) COPYRIGHT IBM CORPORATION 1988
+ * LICENSED MATERIALS - PROPERTY OF IBM
+ * REFER TO COPYRIGHT INSTRUCTIONS FORM NUMBER G120-2083
+ */
+
+#ifndef lint
+static char rcsid[] = "$Header: /afs/athena.mit.edu/astaff/project/moiradev/repository/moira/afssync/utils.c,v 1.7 1992-07-05 13:03:50 probe Exp $";
+#endif
+
+/*	
+       Sherri Nichols
+       Information Technology Center
+       November, 1988
+
+
+       Modified May, 1989 by Jeff Schiller to keep disk file in
+       network byte order
+
+*/
+
+#include <afs/param.h>
+#include <sys/types.h>
+#include <lock.h>
+#include <ubik.h>
+#include <stdio.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include "ptserver.h"
+#include "pterror.h"
+
+long IDHash(x)
+long x;
+{
+    /* returns hash bucket for x */
+    return ((abs(x)) % HASHSIZE);
+}
+
+long NameHash(aname)
+register unsigned char *aname;
+{
+    /* returns hash bucket for aname */
+    register unsigned int hash=0;
+    register int i;
+/* stolen directly from the HashString function in the vol package */
+    for (i=strlen(aname),aname += i-1;i--;aname--)
+	hash = (hash*31) + (*aname-31);
+    return(hash % HASHSIZE);
+}
+
+
+long pr_Write(tt,afd,pos,buff,len)
+struct ubik_trans *tt;
+long afd;
+long pos;
+char *buff;
+long len;
+{
+    /* package up seek and write into one procedure for ease of use */
+    long code;
+    if ((pos < sizeof(cheader)) && (buff != (char *)&cheader + pos)) {
+	fprintf (stderr, "ptserver: dbwrite: Illegal attempt to write a location 0\n");
+	return PRDBFAIL;
+    }
+    code = ubik_Seek(tt,afd,pos);
+    if (code) return code;
+    code = ubik_Write(tt,buff,len);
+    return code;
+}
+
+long pr_Read(tt,afd,pos,buff,len)
+struct ubik_trans *tt;
+long afd;
+long pos;
+char *buff;
+long len;
+{
+    /* same thing for read */
+    long code;
+    code = ubik_Seek(tt,afd,pos);
+    if (code) return code;
+    code = ubik_Read(tt,buff,len);
+    return code;
+}
+
+pr_WriteEntry(tt, afd, pos, tentry)
+struct ubik_trans *tt;
+long afd;
+long pos;
+struct prentry *tentry;
+{
+    long code;
+    register long i;
+    struct prentry nentry;
+
+    if (ntohl(1) != 1) {	/* Need to swap bytes. */
+      bzero (&nentry, sizeof(nentry));	/* make sure reseved fields are zero */
+      nentry.flags = htonl(tentry->flags);
+      nentry.id = htonl(tentry->id);
+      nentry.cellid = htonl(tentry->cellid);
+      nentry.next = htonl(tentry->next);
+      nentry.nextID = htonl(tentry->nextID);
+      nentry.nextName = htonl(tentry->nextName);
+      nentry.owner = htonl(tentry->owner);
+      nentry.creator = htonl(tentry->creator);
+      nentry.ngroups = htonl(tentry->ngroups);
+      nentry.nusers = htonl(tentry->nusers);
+      nentry.count = htonl(tentry->count);
+      nentry.instance = htonl(tentry->instance);
+      nentry.owned = htonl(tentry->owned);
+      nentry.nextOwned = htonl(tentry->nextOwned);
+      nentry.parent = htonl(tentry->parent);
+      nentry.sibling = htonl(tentry->sibling);
+      nentry.child = htonl(tentry->child);
+      strncpy(nentry.name, tentry->name, PR_MAXNAMELEN);
+#ifdef PR_REMEMBER_TIMES
+      nentry.createTime = htonl(tentry->createTime);
+      nentry.addTime = htonl(tentry->addTime);
+      nentry.removeTime = htonl(tentry->removeTime);
+      nentry.changeTime = htonl(tentry->changeTime);
+#endif
+      for (i = 0; i < PRSIZE; i++)
+	nentry.entries[i] = htonl(tentry->entries[i]);
+      tentry = &nentry;
+    }
+    code = pr_Write (tt, afd, pos, (char *)tentry, sizeof(struct prentry));
+    return(code);
+}
+  
+pr_ReadEntry(tt, afd, pos, tentry)
+struct ubik_trans *tt;
+long afd;
+long pos;
+struct prentry *tentry;
+{
+    long code;
+    register long i;
+    struct prentry nentry;
+    code = ubik_Seek(tt, afd, pos);
+    if (code) return (code);
+    if (ntohl(1) == 1) {	/* no swapping needed */
+      code = ubik_Read(tt, (char *) tentry, sizeof(struct prentry));
+      return(code);
+    }
+    code = ubik_Read(tt, (char *) &nentry, sizeof(struct prentry));
+    if (code) return (code);
+    bzero (tentry, sizeof(*tentry));	/* make sure reseved fields are zero */
+    tentry->flags = ntohl(nentry.flags);
+    tentry->id = ntohl(nentry.id);
+    tentry->cellid = ntohl(nentry.cellid);
+    tentry->next = ntohl(nentry.next);
+    tentry->nextID = ntohl(nentry.nextID);
+    tentry->nextName = ntohl(nentry.nextName);
+    tentry->owner = ntohl(nentry.owner);
+    tentry->creator = ntohl(nentry.creator);
+    tentry->ngroups = ntohl(nentry.ngroups);
+    tentry->nusers = ntohl(nentry.nusers);
+    tentry->count = ntohl(nentry.count);
+    tentry->instance = ntohl(nentry.instance);
+    tentry->owned = ntohl(nentry.owned);
+    tentry->nextOwned = ntohl(nentry.nextOwned);
+    tentry->parent = ntohl(nentry.parent);
+    tentry->sibling = ntohl(nentry.sibling);
+    tentry->child = ntohl(nentry.child);
+    strncpy(tentry->name, nentry.name, PR_MAXNAMELEN);
+#ifdef PR_REMEMBER_TIMES
+    tentry->createTime = ntohl(nentry.createTime);
+    tentry->addTime = ntohl(nentry.addTime);
+    tentry->removeTime = ntohl(nentry.removeTime);
+    tentry->changeTime = ntohl(nentry.changeTime);
+#endif
+    for (i = 0; i < PRSIZE; i++)
+      tentry->entries[i] = ntohl(nentry.entries[i]);
+    return(code);
+}
+
+pr_WriteCoEntry(tt, afd, pos, tentry)
+  struct ubik_trans *tt;
+  long afd;
+  long pos;
+  struct contentry *tentry;
+{
+    long code;
+    register long i;
+    struct contentry nentry;
+
+    if (ntohl(1) != 1) {	/* No need to swap */
+	bzero (&nentry, sizeof(nentry)); /* make reseved fields zero */
+	nentry.flags = htonl(tentry->flags);
+	nentry.id = htonl(tentry->id);
+	nentry.cellid = htonl(tentry->cellid);
+	nentry.next = htonl(tentry->next);
+	for (i = 0; i < COSIZE; i++)
+	    nentry.entries[i] = htonl(tentry->entries[i]);
+	tentry = &nentry;
+    }
+    code = pr_Write (tt, afd, pos, (char *)tentry, sizeof(struct contentry));
+    return(code);
+}
+
+pr_ReadCoEntry(tt, afd, pos, tentry)
+struct ubik_trans *tt;
+long afd;
+long pos;
+struct contentry *tentry;
+{
+    long code;
+    register long i;
+    struct contentry nentry;
+    code = ubik_Seek(tt, afd, pos);
+    if (code) return (code);
+    if (ntohl(1) == 1) {	/* No swapping needed. */
+      code = ubik_Read(tt, (char *) tentry, sizeof(struct contentry));
+      return(code);
+    }
+    code = ubik_Read(tt, (char *) &nentry, sizeof(struct contentry));
+    if (code) return (code);
+    bzero (tentry, sizeof(*tentry)); /* make reseved fields zero */
+    tentry->flags = ntohl(nentry.flags);
+    tentry->id = ntohl(nentry.id);
+    tentry->cellid = ntohl(nentry.cellid);
+    tentry->next = ntohl(nentry.next);
+    for (i = 0; i < COSIZE; i++)
+      tentry->entries[i] = ntohl(nentry.entries[i]);
+    return(code);
+}
+
+/* AllocBloc - allocate a free block of storage for entry, returning address of
+ * new entry */
+
+long AllocBlock(at)
+  register struct ubik_trans *at;
+{
+    register long code;
+    long temp;
+    struct prentry tentry;
+
+    if (cheader.freePtr) {
+	/* allocate this dude */
+	temp = ntohl(cheader.freePtr);      
+	code = pr_ReadEntry(at, 0, temp, &tentry);
+	if (code) return 0;
+	cheader.freePtr = htonl(tentry.next);
+	code = pr_Write(at, 0, 8, (char *)&cheader.freePtr, sizeof(cheader.freePtr));
+	if (code != 0) return 0;
+	return temp;
+    }
+    else {
+	/* hosed, nothing on free list, grow file */
+	temp = ntohl(cheader.eofPtr);	/* remember this guy */
+	cheader.eofPtr = htonl(temp + ENTRYSIZE);
+	code = pr_Write(at, 0, 12,(char *) &cheader.eofPtr, sizeof(cheader.eofPtr));
+	if (code != 0) return 0;
+	return temp;
+    }
+}
+
+long FreeBlock(at, pos)
+register struct ubik_trans *at;
+long pos;
+{
+    /* add a block of storage to the free list */
+    register long code;
+    struct prentry tentry;
+
+    bzero(&tentry,sizeof(tentry));
+    tentry.next = ntohl(cheader.freePtr);
+    tentry.flags |= PRFREE;
+    cheader.freePtr = htonl(pos);
+    code = pr_Write(at,0,8, (char *) &cheader.freePtr,sizeof(cheader.freePtr));
+    if (code != 0) return code;
+    code = pr_WriteEntry(at,0,pos,&tentry);
+    if (code != 0) return code;
+    return PRSUCCESS;
+}
+
+long FindByID(at,aid)
+register struct ubik_trans *at;
+long aid;
+{
+    /* returns address of entry if found, 0 otherwise */
+    register long code;
+    long i;
+    struct prentry tentry;
+    long entry;
+
+    if ((aid == PRBADID) || (aid == 0)) return 0;
+    i = IDHash(aid);
+    entry = ntohl(cheader.idHash[i]);
+    if (entry == 0) return entry;
+    bzero(&tentry,sizeof(tentry));
+    code = pr_ReadEntry(at, 0, entry, &tentry);
+    if (code != 0) return 0;
+    if (aid == tentry.id) return entry;
+    entry = tentry.nextID;
+    while (entry != NULL) {
+	bzero(&tentry,sizeof(tentry));
+	code = pr_ReadEntry(at,0,entry,&tentry);
+	if (code != 0) return 0;
+	if (aid == tentry.id) return entry;
+	entry = tentry.nextID;
+    }
+    return 0;
+}
+ 
+
+
+long FindByName(at,aname)    
+register struct ubik_trans *at;
+char aname[PR_MAXNAMELEN];
+{
+    /* ditto */
+    register long code;
+    long i;
+    struct prentry tentry;
+    long entry;
+
+    i = NameHash(aname);
+    entry = ntohl(cheader.nameHash[i]);
+    if (entry == 0) return entry;
+    bzero(&tentry,sizeof(tentry));
+    code = pr_ReadEntry(at, 0, entry,&tentry);
+    if (code != 0) return 0;
+    if ((strncmp(aname,tentry.name,PR_MAXNAMELEN)) == 0) return entry;
+    entry = tentry.nextName;
+    while (entry != NULL) {
+	bzero(&tentry,sizeof(tentry));
+	code = pr_ReadEntry(at,0,entry,&tentry);
+	if (code != 0) return 0;
+	if ((strncmp(aname,tentry.name,PR_MAXNAMELEN)) == 0) return entry;
+	entry = tentry.nextName;
+    }
+    return 0;
+}
+
+long AllocID(at,flag,aid)
+register struct ubik_trans *at;
+long flag;
+long *aid;
+{
+    /* allocs an id from the proper area of address space, based on flag */
+    register long code = 1;
+    register long i = 0;
+    register maxcount = 50;  /* to prevent infinite loops */
+    
+    if (flag & PRGRP) {
+	*aid = ntohl(cheader.maxGroup);
+	while (code && i<maxcount) {
+	    --(*aid);
+	    code = FindByID(at,*aid);
+	    i++;
+	}
+	if (code) return PRNOIDS;
+	cheader.maxGroup = htonl(*aid);
+	code = pr_Write(at,0,16,(char *)&cheader.maxGroup,sizeof(cheader.maxGroup));
+	if (code) return PRDBFAIL;
+	return PRSUCCESS;
+    }
+    else if (flag & PRFOREIGN) {
+	*aid = ntohl(cheader.maxForeign);
+	while (code && i<maxcount) {
+	    ++(*aid);
+	    code = FindByID(at,*aid);
+	    i++;
+	}
+	if (code) return PRNOIDS;
+	cheader.maxForeign = htonl(*aid);
+	code = pr_Write(at,0,24,(char *)&cheader.maxForeign,sizeof(cheader.maxForeign));
+	if (code) return PRDBFAIL;
+	return PRSUCCESS;
+    }
+    else {
+	*aid = ntohl(cheader.maxID);
+	while (code && i<maxcount) {
+	    ++(*aid);
+	    code = FindByID(at,*aid);
+	    i++;
+	}
+	if (code) return PRNOIDS;
+	cheader.maxID = htonl(*aid);
+	code = pr_Write(at,0,20,(char *)&cheader.maxID,sizeof(cheader.maxID));
+	if (code) return PRDBFAIL;
+	return PRSUCCESS;
+    }
+}
+
+long IDToName(at, aid, aname)
+  register struct ubik_trans *at;
+  long aid;
+  char aname[PR_MAXNAMELEN];
+{
+    long temp;
+    struct prentry tentry;
+    register long code;
+
+    temp = FindByID(at,aid);
+    if (temp == 0) return PRNOENT;
+    code = pr_Read (at, 0, temp, (char *)&tentry, sizeof(tentry));
+    if (code) return code;
+    strncpy (aname, tentry.name, PR_MAXNAMELEN);
+    return PRSUCCESS;
+}
+
+long NameToID(at, aname, aid)
+register struct ubik_trans *at;
+char aname[PR_MAXNAMELEN];
+long *aid;
+{
+    register long code;
+    long temp;
+    struct prentry tentry;
+
+    temp = FindByName(at,aname);
+    if (!temp) return PRNOENT;
+    code = pr_ReadEntry(at, 0, temp, &tentry);
+    if (code != 0) return code;
+    *aid = tentry.id;
+    return PRSUCCESS;
+}
+
+long IDCmp(a,b)
+long *a;
+long *b;
+{
+    /* used to sort CPS's so that comparison with acl's is easier */
+    if (*a > *b) return 1;
+    if (*a == *b) return 0;
+    if (*a < *b) return -1;
+}
+
+long RemoveFromIDHash(tt,aid,loc)
+struct ubik_trans *tt;
+long aid;
+long *loc;				/* ??? in case ID hashed twice ??? */
+{
+    /* remove entry designated by aid from id hash table */
+    register long code;
+    long current, trail, i;
+    struct prentry tentry;
+    struct prentry bentry;
+
+    if ((aid == PRBADID) || (aid == 0)) return PRINCONSISTENT;
+    i = IDHash(aid);
+    current = ntohl(cheader.idHash[i]);
+    bzero(&tentry,sizeof(tentry));
+    bzero(&bentry,sizeof(bentry));
+    trail = 0;
+    if (current == NULL) return PRSUCCESS; /* already gone */
+    code = pr_ReadEntry(tt,0,current,&tentry);
+    if (code) return PRDBFAIL;
+    while (aid != tentry.id) {
+	trail = current;
+	current = tentry.nextID;
+	if (current == NULL) break;
+	code = pr_ReadEntry(tt,0,current,&tentry);
+	if (code) return PRDBFAIL;
+    }
+    if (current == NULL) return PRSUCCESS;  /* we didn't find him, so he's already gone */
+    if (trail == NULL) {
+	/* it's the first entry! */
+	cheader.idHash[i] = htonl(tentry.nextID);
+	code = pr_Write(tt,0,72+HASHSIZE*4+i*4,(char *)&cheader.idHash[i],sizeof(cheader.idHash[i]));
+	if (code) return PRDBFAIL;
+    }
+    else {
+	code = pr_ReadEntry(tt,0,trail, &bentry);
+	if (code) return PRDBFAIL;
+	bentry.nextID = tentry.nextID;
+	code = pr_WriteEntry(tt,0,trail,&bentry);
+    }
+    *loc = current;
+    return PRSUCCESS;
+}
+
+long AddToIDHash(tt, aid, loc)
+struct ubik_trans *tt;
+long aid;
+long loc;				/* ??? */
+{
+    /* add entry at loc designated by aid to id hash table */
+    register long code;
+    long i;
+    struct prentry tentry;
+
+    if ((aid == PRBADID) || (aid == 0)) return PRINCONSISTENT;
+    i = IDHash(aid);
+    bzero(&tentry,sizeof(tentry));
+    code = pr_ReadEntry(tt,0,loc,&tentry);
+    if (code) return PRDBFAIL;
+    tentry.nextID = ntohl(cheader.idHash[i]);
+    cheader.idHash[i] = htonl(loc);
+    code = pr_WriteEntry(tt,0,loc,&tentry);
+    if (code) return PRDBFAIL;
+    code = pr_Write(tt,0,72+HASHSIZE*4+i*4,(char *)&cheader.idHash[i],sizeof(cheader.idHash[i]));
+    if (code) return PRDBFAIL;
+    return PRSUCCESS;
+}
+
+long RemoveFromNameHash(tt,aname,loc)
+struct ubik_trans *tt;
+char *aname;
+long *loc;
+{
+    /* remove from name hash */
+    register long code;
+    long current, trail, i;
+    struct prentry tentry;
+    struct prentry bentry;
+
+    i = NameHash(aname);
+    current = ntohl(cheader.nameHash[i]);
+    bzero(&tentry,sizeof(tentry));
+    bzero(&bentry,sizeof(bentry));
+    trail = 0;
+    if (current == NULL) return PRSUCCESS;  /* already gone */
+    code = pr_ReadEntry(tt,0,current,&tentry);
+    if (code) return PRDBFAIL;
+    while (strcmp(aname,tentry.name)) {
+	trail = current;
+	current = tentry.nextName;
+	if (current == NULL) break;
+	code = pr_ReadEntry(tt,0,current,&tentry);
+	if (code) return PRDBFAIL;
+    }
+    if (current == NULL) return PRSUCCESS;  /* we didn't find him, already gone */
+    if (trail == NULL) {
+	/* it's the first entry! */
+	cheader.nameHash[i] = htonl(tentry.nextName);
+	code = pr_Write(tt,0,72+i*4,(char *)&cheader.nameHash[i],sizeof(cheader.nameHash[i]));
+	if (code) return PRDBFAIL;
+    }
+    else {
+	code = pr_ReadEntry(tt,0,trail, &bentry);
+	if (code) return PRDBFAIL;
+	bentry.nextName = tentry.nextName;
+	code = pr_WriteEntry(tt,0,trail,&bentry);
+    }
+    *loc = current;
+    return PRSUCCESS;
+}
+
+long AddToNameHash(tt, aname, loc)
+struct ubik_trans *tt;
+char *aname;
+long loc;
+{
+    /* add to name hash */
+    register long code;
+    long i;
+    struct prentry tentry;
+
+    i = NameHash(aname);
+    bzero(&tentry,sizeof(tentry));
+    code = pr_ReadEntry(tt,0,loc,&tentry);
+    if (code) return PRDBFAIL;
+    tentry.nextName = ntohl(cheader.nameHash[i]);
+    cheader.nameHash[i] = htonl(loc);
+    code = pr_WriteEntry(tt,0,loc,&tentry);
+    if (code) return PRDBFAIL;
+    code = pr_Write(tt,0,72+i*4,(char *)&cheader.nameHash[i],sizeof(cheader.nameHash[i]));
+    if (code) return PRDBFAIL;
+    return PRSUCCESS;
+}
+
+long AddToOwnerChain(at,gid,oid)
+  struct ubik_trans *at;
+  long gid;
+  long oid;
+{
+    /* add entry designated by gid to owner chain of entry designated by oid */
+    register long code;
+    long loc;
+    struct prentry tentry;
+    struct prentry gentry;
+    long gloc;
+
+    loc = FindByID(at,oid);
+    if (!loc) return PRNOENT;
+    code = pr_ReadEntry(at,0,loc,&tentry);
+    if (code != 0) return PRDBFAIL;
+    if (oid == gid) {			/* added it to its own chain */
+	tentry.nextOwned = tentry.owned;
+	tentry.owned = loc;
+    } else {
+	gloc = FindByID(at,gid);
+	code = pr_ReadEntry(at,0,gloc,&gentry);
+	if (code != 0) return PRDBFAIL;
+	gentry.nextOwned = tentry.owned;
+	tentry.owned = gloc;
+	code = pr_WriteEntry(at,0,gloc,&gentry);
+	if (code != 0) return PRDBFAIL;
+    }
+    code = pr_WriteEntry(at,0,loc,&tentry);
+    if (code != 0) return PRDBFAIL;
+    return PRSUCCESS;
+}
+
+/* RemoveFromOwnerChain - remove gid from owner chain for oid */
+
+long RemoveFromOwnerChain(at,gid,oid)
+  struct ubik_trans *at;
+  long gid;
+  long oid;
+{
+    register long code;
+    long nptr;
+    struct prentry thisEntry;
+    struct prentry thatEntry;
+    struct prentry *te;			/* pointer to current (this) entry */
+    struct prentry *le;			/* pointer to previous (last) entry */
+    long loc, lastLoc;
+
+    loc = FindByID(at,oid);
+    if (!loc) return PRNOENT;
+    code = pr_ReadEntry (at, 0, loc, &thisEntry);
+    if (code != 0) return PRDBFAIL;
+    le =  &thisEntry;
+    lastLoc = 0;
+    nptr = thisEntry.owned;
+    while (nptr != NULL) {
+	if (nptr == lastLoc) te = le;
+	else {
+	    if (&thisEntry == le) te = &thatEntry;
+	    else te = &thisEntry;
+	    code = pr_ReadEntry (at, 0, nptr, te);
+	    if (code != 0) return PRDBFAIL;
+	}
+	if (te->id == gid) {
+	    /* found it */
+	    if (lastLoc == 0) {		/* modifying first of chain */
+		le->owned = te->nextOwned;
+		lastLoc = loc;		/* so we write to correct location */
+	    }
+	    else le->nextOwned = te->nextOwned;
+	    te->nextOwned = 0;
+	    if (te != le) {
+		code = pr_WriteEntry (at, 0, nptr, te);
+		if (code != 0) return PRDBFAIL;
+	    }
+	    code = pr_WriteEntry (at, 0, lastLoc, le);
+	    if (code != 0) return PRDBFAIL;
+	    return PRSUCCESS;
+	}
+	lastLoc = nptr;
+	le = te;
+	nptr = te->nextOwned;
+    }
+    return PRSUCCESS;			/* already removed? */
+}
+
+/* AddToOrphan - add gid to orphan list, as it's owner has died */
+
+long AddToOrphan(at,gid)
+  struct ubik_trans *at;
+  long gid;
+{
+    register long code;
+    long loc;
+    struct prentry tentry;
+
+    loc = FindByID(at,gid);
+    if (!loc) return PRNOENT;
+    code = pr_ReadEntry(at,0,loc,&tentry);
+    if (code != 0) return PRDBFAIL;
+    tentry.nextOwned = ntohl(cheader.orphan);
+    code = set_header_word (at, orphan, htonl(loc));
+    if (code != 0) return PRDBFAIL;
+    tentry.owner = 0;			/* so there's no confusion later */
+    code = pr_WriteEntry(at,0,loc,&tentry);
+    if (code != 0) return PRDBFAIL;
+    return PRSUCCESS;
+}
+
+long RemoveFromOrphan(at,gid)
+struct ubik_trans *at;
+long gid;
+{
+    /* remove gid from the orphan list */
+    register long code;
+    long loc;
+    long nptr;
+    struct prentry tentry;
+    struct prentry bentry;
+
+    loc = FindByID(at,gid);
+    if (!loc) return PRNOENT;
+    code = pr_ReadEntry(at,0,loc,&tentry);
+    if (code != 0) return PRDBFAIL;
+    if (cheader.orphan == htonl(loc)) {
+	cheader.orphan = htonl(tentry.nextOwned);
+	tentry.nextOwned = 0;
+	code = pr_Write(at,0,32,(char *)&cheader.orphan,sizeof(cheader.orphan));
+	if (code != 0) return PRDBFAIL;
+	code = pr_WriteEntry(at,0,loc,&tentry);
+	if (code != 0) return PRDBFAIL;
+	return PRSUCCESS;
+    }
+    nptr = ntohl(cheader.orphan);
+    bzero(&bentry,sizeof(bentry));
+    loc = 0;
+    while (nptr != NULL) {
+	code = pr_ReadEntry(at,0,nptr,&tentry);
+	if (code != 0) return PRDBFAIL;
+	if (gid == tentry.id) {
+	    /* found it */
+	    bentry.nextOwned = tentry.nextOwned;
+	    tentry.nextOwned = 0;
+	    code = pr_WriteEntry(at,0,loc,&bentry);
+	    if (code != 0) return PRDBFAIL;
+	    code = pr_WriteEntry(at,0,nptr,&tentry);
+	    if (code != 0) return PRDBFAIL;
+	    return PRSUCCESS;
+	}
+	loc = nptr;
+	nptr = tentry.nextOwned;
+	bcopy(&tentry,&bentry, sizeof(tentry));
+    }
+    return PRSUCCESS;
+}
+
+long IsOwnerOf(at,aid,gid)
+struct ubik_trans *at;
+long aid;
+long gid;
+{
+    /* returns 1 if aid is the owner of gid, 0 otherwise */
+    register long code;
+    struct prentry tentry;
+    long loc;
+
+    loc = FindByID(at,gid);
+    if (!loc) return 0;
+    code = pr_ReadEntry(at,0,loc,&tentry);
+    if (code != 0) return 0;
+    if (tentry.owner == aid) return 1;
+    return 0;
+}
+
+long OwnerOf(at,gid)
+struct ubik_trans *at;
+long gid;
+{
+    /* returns the owner of gid */
+    register long code;
+    long loc;
+    struct prentry tentry;
+
+    loc = FindByID(at,gid);
+    if (!loc) return 0;
+    code = pr_ReadEntry(at,0,loc,&tentry);
+    if (code != 0) return 0;
+    return tentry.owner;
+}
+    
+
+long IsAMemberOf(at,aid,gid)
+struct ubik_trans *at;
+long aid;
+long gid;
+{
+    /* returns true if aid is a member of gid */
+    struct prentry tentry;
+    struct contentry centry;
+    register long code;
+    long i;
+    long loc;
+
+    /* special case anyuser and authuser */
+    if (gid == ANYUSERID) return 1;
+    if (gid == AUTHUSERID && aid != ANONYMOUSID) return 1;
+    if ((gid == 0) || (aid == 0)) return 0;
+    loc = FindByID(at,gid);
+    if (!loc) return 0;
+    bzero(&tentry,sizeof(tentry));
+    code = pr_ReadEntry(at, 0, loc,&tentry);
+    if (code) return 0;
+    if (!(tentry.flags & PRGRP)) return 0;
+    for (i= 0;i<PRSIZE;i++) {
+	if (tentry.entries[i] == 0) return 0;
+	if (tentry.entries[i] == aid) return 1;
+    }
+    if (tentry.next) {
+	loc = tentry.next;
+	while (loc) {
+	    bzero(&centry,sizeof(centry));
+	    code = pr_ReadCoEntry(at,0,loc,&centry);
+	    if (code) return 0;
+	    for (i=0;i<COSIZE;i++) {
+		if (centry.entries[i] == aid) return 1;
+		if (centry.entries[i] == 0) return 0;
+	    }
+	    loc = centry.next;
+	}
+    }
+    return 0;  /* actually, should never get here */
+}
--- debathena-moira-4.0.0+cvs20080304.orig/afssync/vis.c
+++ debathena-moira-4.0.0+cvs20080304/afssync/vis.c
@@ -0,0 +1,424 @@
+/* $Id: vis.c,v 1.1 2001-10-23 19:35:56 zacheiss Exp $
+ * vis functions - visually encode characters
+ * Originally from OpenBSD
+ */
+
+/*-
+ * Copyright (c) 1989, 1993
+ *      The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by the University of
+ *      California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef HAVE_STRVIS
+#include "vis.h"
+/*
+ * vis - visually encode characters
+ */
+char *
+vis(dst, c, flag, nextc)
+        register char *dst;
+        int c, nextc;
+        register int flag;
+{
+        if (isvisible(c)) {
+                *dst++ = c;
+                if (c == '\\' && (flag & VIS_NOSLASH) == 0)
+                        *dst++ = '\\';
+                *dst = '\0';
+                return (dst);
+        }
+
+        if (flag & VIS_CSTYLE) {
+                switch(c) {
+                case '\n':
+                        *dst++ = '\\';
+                        *dst++ = 'n';
+                        goto done;
+                case '\r':
+                        *dst++ = '\\';
+                        *dst++ = 'r';
+                        goto done;
+                case '\b':
+                        *dst++ = '\\';
+                        *dst++ = 'b';
+                        goto done;
+#ifdef __STDC__
+                case '\a':
+#else
+                case '\007':
+#endif
+                        *dst++ = '\\';
+                        *dst++ = 'a';
+                        goto done;
+                case '\v':
+                        *dst++ = '\\';
+                        *dst++ = 'v';
+                        goto done;
+                case '\t':
+                        *dst++ = '\\';
+                        *dst++ = 't';
+                        goto done;
+                case '\f':
+                        *dst++ = '\\';
+                        *dst++ = 'f';
+                        goto done;
+                case ' ':
+                        *dst++ = '\\';
+                        *dst++ = 's';
+                        goto done;
+                case '\0':
+                        *dst++ = '\\';
+                        *dst++ = '0';
+                        if (isoctal(nextc)) {
+                                *dst++ = '0';
+                                *dst++ = '0';
+                        }
+                        goto done;
+                }
+        }
+        if (((c & 0177) == ' ') || (flag & VIS_OCTAL)) {        
+                *dst++ = '\\';
+                *dst++ = ((u_char)c >> 6 & 07) + '0';
+                *dst++ = ((u_char)c >> 3 & 07) + '0';
+                *dst++ = ((u_char)c & 07) + '0';
+                goto done;
+        }
+        if ((flag & VIS_NOSLASH) == 0)
+                *dst++ = '\\';
+        if (c & 0200) {
+                c &= 0177;
+                *dst++ = 'M';
+        }
+        if (iscntrl(c)) {
+                *dst++ = '^';
+                if (c == 0177)
+                        *dst++ = '?';
+                else
+                        *dst++ = c + '@';
+        } else {
+                *dst++ = '-';
+                *dst++ = c;
+        }
+done:
+        *dst = '\0';
+        return (dst);
+}
+
+/*
+ * strvis, strnvis, strvisx - visually encode characters from src into dst
+ *      
+ *      Dst must be 4 times the size of src to account for possible
+ *      expansion.  The length of dst, not including the trailing NULL,
+ *      is returned. 
+ *
+ *      Strnvis will write no more than siz-1 bytes (and will NULL terminate).
+ *      The number of bytes needed to fully encode the string is returned.
+ *
+ *      Strvisx encodes exactly len bytes from src into dst.
+ *      This is useful for encoding a block of data.
+ */
+int
+strvis(dst, src, flag)
+        register char *dst;
+        register const char *src;
+        int flag;
+{
+        register char c;
+        char *start;
+
+        for (start = dst; (c = *src);)
+                dst = vis(dst, c, flag, *++src);
+        *dst = '\0';
+        return (dst - start);
+}
+
+int
+strnvis(dst, src, siz, flag)
+        register char *dst;
+        register const char *src;
+        size_t siz;
+        int flag;
+{
+        register char c;
+        char *start, *end;
+
+        for (start = dst, end = start + siz - 1; (c = *src) && dst < end; ) {
+                if (isvisible(c)) {
+                        *dst++ = c;
+                        if (c == '\\' && (flag & VIS_NOSLASH) == 0) {
+                                /* need space for the extra '\\' */
+                                if (dst < end)
+                                        *dst++ = '\\';
+                                else {
+                                        dst--;
+                                        break;
+                                }
+                        }
+                        src++;
+                } else {
+                        /* vis(3) requires up to 4 chars */
+                        if (dst + 3 < end)
+                                dst = vis(dst, c, flag, *++src);
+                        else
+                                break;
+                }
+        }
+        *dst = '\0';
+        if (dst >= end) {
+                char tbuf[5];
+
+                /* adjust return value for truncation */
+                while ((c = *src))
+                        dst += vis(tbuf, c, flag, *++src) - tbuf;
+        }
+        return (dst - start);
+}
+
+int
+strvisx(dst, src, len, flag)
+        register char *dst;
+        register const char *src;
+        register size_t len;
+        int flag;
+{
+        register char c;
+        char *start;
+
+        for (start = dst; len > 1; len--) {
+                c = *src;
+                dst = vis(dst, c, flag, *++src);
+        }
+        if (len)
+                dst = vis(dst, *src, flag, '\0');
+        *dst = '\0';
+        return (dst - start);
+}
+
+/*
+ * unvis - decode characters previously encoded by vis
+ */
+int
+#ifdef __STDC__
+unvis(char *cp, char c, int *astate, int flag)
+#else
+unvis(cp, c, astate, flag)
+        char *cp;
+        char c;
+        int *astate, flag;
+#endif
+{
+
+        if (flag & UNVIS_END) {
+                if (*astate == S_OCTAL2 || *astate == S_OCTAL3) {
+                        *astate = S_GROUND;
+                        return (UNVIS_VALID);
+                } 
+                return (*astate == S_GROUND ? UNVIS_NOCHAR : UNVIS_SYNBAD);
+        }
+
+        switch (*astate) {
+
+        case S_GROUND:
+                *cp = 0;
+                if (c == '\\') {
+                        *astate = S_START;
+                        return (0);
+                } 
+                *cp = c;
+                return (UNVIS_VALID);
+
+        case S_START:
+                switch(c) {
+                case '\\':
+                        *cp = c;
+                        *astate = S_GROUND;
+                        return (UNVIS_VALID);
+                case '0': case '1': case '2': case '3':
+                case '4': case '5': case '6': case '7':
+                        *cp = (c - '0');
+                        *astate = S_OCTAL2;
+                        return (0);
+                case 'M':
+                        *cp = (char) 0200;
+                        *astate = S_META;
+                        return (0);
+                case '^':
+                        *astate = S_CTRL;
+                        return (0);
+                case 'n':
+                        *cp = '\n';
+                        *astate = S_GROUND;
+                        return (UNVIS_VALID);
+                case 'r':
+                        *cp = '\r';
+                        *astate = S_GROUND;
+                        return (UNVIS_VALID);
+                case 'b':
+                        *cp = '\b';
+                        *astate = S_GROUND;
+                        return (UNVIS_VALID);
+                case 'a':
+                        *cp = '\007';
+                        *astate = S_GROUND;
+                        return (UNVIS_VALID);
+                case 'v':
+                        *cp = '\v';
+                        *astate = S_GROUND;
+                        return (UNVIS_VALID);
+                case 't':
+                        *cp = '\t';
+                        *astate = S_GROUND;
+                        return (UNVIS_VALID);
+                case 'f':
+                        *cp = '\f';
+                        *astate = S_GROUND;
+                        return (UNVIS_VALID);
+                case 's':
+                        *cp = ' ';
+                        *astate = S_GROUND;
+                        return (UNVIS_VALID);
+                case 'E':
+                        *cp = '\033';
+                        *astate = S_GROUND;
+                        return (UNVIS_VALID);
+                case '\n':
+                        /*
+                         * hidden newline
+                         */
+                        *astate = S_GROUND;
+                        return (UNVIS_NOCHAR);
+                case '$':
+                        /*
+                         * hidden marker
+                         */
+                        *astate = S_GROUND;
+                        return (UNVIS_NOCHAR);
+                }
+                *astate = S_GROUND;
+                return (UNVIS_SYNBAD);
+                 
+        case S_META:
+                if (c == '-')
+                        *astate = S_META1;
+                else if (c == '^')
+                        *astate = S_CTRL;
+                else {
+                        *astate = S_GROUND;
+                        return (UNVIS_SYNBAD);
+                }
+                return (0);
+                 
+        case S_META1:
+                *astate = S_GROUND;
+                *cp |= c;
+                return (UNVIS_VALID);
+                 
+        case S_CTRL:
+                if (c == '?')
+                        *cp |= 0177;
+                else
+                        *cp |= c & 037;
+                *astate = S_GROUND;
+                return (UNVIS_VALID);
+
+        case S_OCTAL2:        /* second possible octal digit */
+                if (isoctal(c)) {
+                        /* 
+                         * yes - and maybe a third 
+                         */
+                        *cp = (*cp << 3) + (c - '0');
+                        *astate = S_OCTAL3;        
+                        return (0);
+                } 
+                /* 
+                 * no - done with current sequence, push back passed char 
+                 */
+                *astate = S_GROUND;
+                return (UNVIS_VALIDPUSH);
+
+        case S_OCTAL3:        /* third possible octal digit */
+                *astate = S_GROUND;
+                if (isoctal(c)) {
+                        *cp = (*cp << 3) + (c - '0');
+                        return (UNVIS_VALID);
+                }
+                /*
+                 * we were done, push back passed char
+                 */
+                return (UNVIS_VALIDPUSH);
+                        
+        default:        
+                /* 
+                 * decoder in unknown state - (probably uninitialized) 
+                 */
+                *astate = S_GROUND;
+                return (UNVIS_SYNBAD);
+        }
+}
+
+/*
+ * strunvis - decode src into dst 
+ *
+ *      Number of chars decoded into dst is returned, -1 on error.
+ *      Dst is null terminated.
+ */
+
+int
+strunvis(dst, src)
+        register char *dst;
+        register const char *src;
+{
+        register char c;
+        char *start = dst;
+        int state = 0;
+
+        while ((c = *src++)) {
+        again:
+                switch (unvis(dst, c, &state, 0)) {
+                case UNVIS_VALID:
+                        dst++;
+                        break;
+                case UNVIS_VALIDPUSH:
+                        dst++;
+                        goto again;
+                case 0:
+                case UNVIS_NOCHAR:
+                        break;
+                default:
+                        return (-1);
+                }
+        }
+        if (unvis(dst, c, &state, UNVIS_END) == UNVIS_VALID)
+                dst++;
+        *dst = '\0';
+        return (dst - start);
+}
+
+#endif /* HAVE_STRVIS */
--- debathena-moira-4.0.0+cvs20080304.orig/afssync/vis.h
+++ debathena-moira-4.0.0+cvs20080304/afssync/vis.h
@@ -0,0 +1,98 @@
+/* $Id: vis.h,v 1.1 2001-10-23 19:35:56 zacheiss Exp $
+ * vis functions - visually encode characters
+ * Originally from OpenBSD
+ */
+
+/*-
+ * Copyright (c) 1989, 1993
+ *      The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by the University of
+ *      California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <limits.h>
+#include <ctype.h>
+/*
+ * to select alternate encoding format
+ */
+#define VIS_OCTAL         0x01        /* use octal \ddd format */
+#define VIS_CSTYLE        0x02        /* use \[nrft0..] where appropriate */
+/*
+ * to alter set of characters encoded (default is to encode all
+ * non-graphic except space, tab, and newline).
+ */
+#define VIS_SP            0x04        /* also encode space */
+#define VIS_TAB           0x08        /* also encode tab */
+#define VIS_NL            0x10        /* also encode newline */
+#define VIS_WHITE         (VIS_SP | VIS_TAB | VIS_NL)
+#define VIS_SAFE          0x20        /* only encode "unsafe" characters */
+
+#define VIS_NOSLASH       0x40        /* inhibit printing '\' */
+
+/*
+ * unvis return codes
+ */
+#define UNVIS_VALID     1        /* character valid */
+#define UNVIS_VALIDPUSH 2        /* character valid, push back passed char */
+#define UNVIS_NOCHAR    3        /* valid sequence, no character produced */
+#define UNVIS_SYNBAD   -1        /* unrecognized escape sequence */
+#define UNVIS_ERROR    -2        /* decoder in unknown state (unrecoverable) */
+
+/*
+ * unvis flags
+ */
+#define UNVIS_END       1        /* no more characters */
+
+#define isoctal(c)        (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
+#define isvisible(c)    (((u_int)(c) <= UCHAR_MAX && isascii((u_char)(c)) && \
+                                isgraph((u_char)(c))) ||                     \
+                                ((flag & VIS_SP) == 0 && (c) == ' ') ||      \
+                                ((flag & VIS_TAB) == 0 && (c) == '\t') ||    \
+                                ((flag & VIS_NL) == 0 && (c) == '\n') ||     \
+                                ((flag & VIS_SAFE) &&                        \
+                                ((c) == '\b' || (c) == '\007' || (c) == '\r')))
+
+/*
+ * decode driven by state machine
+ */
+#define S_GROUND        0        /* haven't seen escape char */
+#define S_START         1        /* start decoding special sequence */
+#define S_META          2        /* metachar started (M) */
+#define S_META1         3        /* metachar more, regular char (-) */
+#define S_CTRL          4        /* control char started (^) */
+#define S_OCTAL2        5        /* octal digit 2 */
+#define S_OCTAL3        6        /* octal digit 3 */
+
+char    *vis(char *, int, int, int);
+int     strvis(char *, const char *, int);
+int     strnvis(char *, const char *, size_t, int);
+int     strvisx(char *, const char *, size_t, int);
+int     strunvis(char *, const char *);
+int     unvis(char *, char, int *, int);
--- debathena-moira-4.0.0+cvs20080304.orig/clients/chpobox/chpobox.c
+++ debathena-moira-4.0.0+cvs20080304/clients/chpobox/chpobox.c
@@ -1,4 +1,4 @@
-/* $Id: chpobox.c,v 1.5 2000-08-10 06:52:05 zacheiss Exp $
+/* $Id: chpobox.c,v 1.6 2008-05-16 16:49:38 zacheiss Exp $
  *
  * Talk to the Moira database to change a person's home mail machine. This may
  * be an Athena machine, or a completely arbitrary address.
@@ -36,7 +36,9 @@
 #include <getopt.h>
 #endif
 
-RCSID("$Header: /afs/athena.mit.edu/astaff/project/moiradev/repository/moira/clients/chpobox/chpobox.c,v 1.5 2000-08-10 06:52:05 zacheiss Exp $");
+#define argis(a, b) (!strcmp(*arg + 1, a) || !strcmp(*arg + 1, b))
+
+RCSID("$Header: /afs/athena.mit.edu/astaff/project/moiradev/repository/moira/clients/chpobox/chpobox.c,v 1.6 2008-05-16 16:49:38 zacheiss Exp $");
 
 int get_pobox(int argc, char **argv, void *callarg);
 void usage(void);
@@ -49,6 +51,8 @@
 {
   char *mrarg[3];
   char *address, *uname;
+  char **arg = argv;
+  char *server = NULL;
   int c, setflag, splitflag, prevflag, status;
 
   setflag = splitflag = prevflag = 0;
@@ -62,35 +66,50 @@
   if (argc > 5)
     usage();
 
-  while ((c = getopt(argc, argv, "s:S:pu:")) != -1)
-    switch (c)
-      {
-      case 's':
-	setflag++;
-	address = optarg;
-	break;
-
-      case 'S':
-	splitflag++;
-	address = optarg;
-	break;
-
-      case 'p':
-	prevflag++;
-	break;
-
-      case 'u':
-	uname = optarg;
-	break;
-
-      default:
+  while (++arg - argv < argc)
+    {
+      if (**arg == '-')
+	{
+	  if (argis("s", "set")) {
+	    if (arg - argv < argc - 1) {
+	      arg++;
+	      setflag++;
+	      address = *arg;
+	    } else
+	      usage();
+	  }
+	  else if (argis("S", "split")) {
+	    if (arg - argv < argc - 1) {
+	      arg++;
+	      splitflag++;
+	      address = *arg;
+	    } else
+	      usage();
+	  }
+	  else if (argis("p", "previous"))
+	    prevflag++;
+	  else if (argis("u", "username")) {
+	    if (arg - argv < argc - 1) {
+	      arg++;
+	      uname = *arg;
+	    } else
+	      usage();
+	  }
+	  else if (argis("db", "database")) {
+	    if (arg - argv < argc - 1) {
+	      arg++;
+	      server = *arg;
+	    } else
+	      usage();
+	  }
+	}
+      else if (uname == NULL)
+	uname = *arg;
+      else
 	usage();
-	break;
-      }
-  if (argc == 2 && optind == 1 && !uname)
-    uname = argv[optind++];
+    }
 
-  if (optind != argc || (prevflag + splitflag + setflag > 1))
+  if (prevflag + splitflag + setflag > 1)
     usage();
 
   if (!uname)
@@ -101,7 +120,7 @@
     }
   mrarg[0] = uname;
 
-  if (mrcl_connect(NULL, "chpobox", 2, 1) != MRCL_SUCCESS)
+  if (mrcl_connect(server, "chpobox", 2, 1) != MRCL_SUCCESS)
     exit(1);
 
   if (setflag || splitflag)
@@ -180,6 +199,6 @@
 
 void usage(void)
 {
-  fprintf(stderr, "Usage: %s [-s|-S address] [-p] [-u user]\n", whoami);
+  fprintf(stderr, "Usage: %s [-s|-S address] [-p] [-u user] [-db database]\n", whoami);
   exit(1);
 }
--- debathena-moira-4.0.0+cvs20080304.orig/clients/moira/cluster.c
+++ debathena-moira-4.0.0+cvs20080304/clients/moira/cluster.c
@@ -1,4 +1,4 @@
-/* $Id: cluster.c,v 1.68 2007-11-29 22:56:02 zacheiss Exp $
+/* $Id: cluster.c,v 1.69 2008-04-22 17:44:37 zacheiss Exp $
  *
  *	This is the file cluster.c for the Moira Client, which allows users
  *      to quickly and easily maintain most parts of the Moira database.
@@ -215,7 +215,7 @@
 
 /* -------------------- General Functions -------------------- */
 
-static char aliasbuf[BUFSIZ];
+static char aliasbuf[BUFSIZ * 2];
 
 void PrintAliases(char **info)
 {
--- debathena-moira-4.0.0+cvs20080304.orig/gen/nagios-colo.gen
+++ debathena-moira-4.0.0+cvs20080304/gen/nagios-colo.gen
@@ -1,6 +1,6 @@
 #!/moira/bin/perl -Tw
 
-# $Id: nagios-colo.gen,v 1.5 2007-09-05 21:32:41 jweiss Exp $
+# $Id: nagios-colo.gen,v 1.6 2008-04-17 17:24:36 zacheiss Exp $
 # The following exit codes are defined and MUST BE CONSISTENT with the
 # error codes the library uses:
 $MR_DBMS_ERR = 47836421;
@@ -40,6 +40,7 @@
 	host_name		$name
 	alias			$name
 	address			$name
+	contact_groups          colo,dost
 	use			generic-host
 	}
 
@@ -74,7 +75,6 @@
 define hostgroup{
         hostgroup_name          colo-hosts
         alias                   colo-hosts
-        contact_groups          colo,dost
 END
 
 print OUT "\tmembers\t\t\t";
--- debathena-moira-4.0.0+cvs20080304.orig/gen/nagios-printers.gen
+++ debathena-moira-4.0.0+cvs20080304/gen/nagios-printers.gen
@@ -1,6 +1,6 @@
 #!/moira/bin/perl -Tw
 
-# $Id: nagios-printers.gen,v 1.2 2007-07-12 17:42:37 jweiss Exp $
+# $Id: nagios-printers.gen,v 1.3 2008-04-17 17:24:36 zacheiss Exp $
 # The following exit codes are defined and MUST BE CONSISTENT with the
 # error codes the library uses:
 $MR_DBMS_ERR = 47836421;
@@ -33,6 +33,7 @@
 	host_name		$name
 	alias			$name
 	address			$name
+	contact_groups          ops-printers
 	use			generic-host
 	}
 
@@ -82,7 +83,6 @@
 define hostgroup{
         hostgroup_name          printers
         alias                   printers
-        contact_groups          ops-printers
 END
 
 print OUT "\tmembers\t\t";
--- debathena-moira-4.0.0+cvs20080304.orig/gen/nagios-wsh.gen
+++ debathena-moira-4.0.0+cvs20080304/gen/nagios-wsh.gen
@@ -1,6 +1,6 @@
 #!/moira/bin/perl -Tw
 
-# $Id: nagios-wsh.gen,v 1.4 2008-02-06 23:40:30 jweiss Exp $
+# $Id: nagios-wsh.gen,v 1.5 2008-04-17 17:24:37 zacheiss Exp $
 # The following exit codes are defined and MUST BE CONSISTENT with the
 # error codes the library uses:
 $MR_DBMS_ERR = 47836421;
@@ -40,6 +40,7 @@
 	host_name		$name
 	alias			$name
 	address			$name
+	contact_groups          wsh
 	use			generic-host
 	}
 
@@ -208,7 +209,6 @@
 define hostgroup{
         hostgroup_name          wsh-hosts
         alias                   wsh-hosts
-        contact_groups          wsh
 END
 
 print OUT "\tmembers\t\t\t";
--- debathena-moira-4.0.0+cvs20080304.orig/include/moira.h
+++ debathena-moira-4.0.0+cvs20080304/include/moira.h
@@ -1,4 +1,4 @@
-/* $Id: moira.h,v 1.33 2006-08-22 17:36:25 zacheiss Exp $
+/* $Id: moira.h,v 1.34 2008-04-17 20:51:16 zacheiss Exp $
  *
  * Copyright (C) 1987-1998 by the Massachusetts Institute of Technology
  *
@@ -18,6 +18,7 @@
 #endif /*_WIN32 */
 
 /* return values from queries (and error codes) */
+#include <stdlib.h>
 #include <sys/types.h>
 #include <com_err.h>
 #include "mr_et.h"
--- debathena-moira-4.0.0+cvs20080304.orig/lib/mr_et.et
+++ debathena-moira-4.0.0+cvs20080304/lib/mr_et.et
@@ -1,4 +1,4 @@
-# $Id: mr_et.et,v 1.30 2002-12-03 21:14:57 zacheiss Exp $
+# $Id: mr_et.et,v 1.31 2008-05-16 16:50:33 zacheiss Exp $
 	error_table sms
 
 ec	MR_NOT_CONNECTED,
@@ -234,4 +234,7 @@
 ec      MR_CONTAINER_NO_PARENT,
 	"Parent container does not exist"
 
+ec	MR_BAD_MAIL_STRING,
+	"Address refers to nonexistent domain or MIT internal mail server"
+
 	end
--- debathena-moira-4.0.0+cvs20080304.orig/regtape/staff.pc
+++ debathena-moira-4.0.0+cvs20080304/regtape/staff.pc
@@ -1,4 +1,4 @@
-/* $Id: staff.pc,v 1.8 2004-09-24 19:05:07 zacheiss Exp $
+/* $Id: staff.pc,v 1.9 2008-03-31 21:00:43 zacheiss Exp $
  *
  * Load data into Moira from Personnel Office data file
  *
@@ -19,7 +19,7 @@
 
 EXEC SQL INCLUDE sqlca;
 
-RCSID("$Header: /afs/athena.mit.edu/astaff/project/moiradev/repository/moira/regtape/staff.pc,v 1.8 2004-09-24 19:05:07 zacheiss Exp $");
+RCSID("$Header: /afs/athena.mit.edu/astaff/project/moiradev/repository/moira/regtape/staff.pc,v 1.9 2008-03-31 21:00:43 zacheiss Exp $");
 
 /* File format is:
  *
@@ -174,9 +174,6 @@
 		  &ends_iv, &ends_v);
   LookForJrAndIII(e.first, &ends_jr, &ends_sr, &ends_ii, &ends_iii,
 		  &ends_iv, &ends_v);
-  FixCase(e.last);
-  FixCase(e.first);
-  FixCase(e.middle);
 
   e.name = buf;
   if (*e.middle)
--- debathena-moira-4.0.0+cvs20080304.orig/server/mr_server.h
+++ debathena-moira-4.0.0+cvs20080304/server/mr_server.h
@@ -1,4 +1,4 @@
-/* $Id: mr_server.h,v 1.64 2007-11-29 18:09:09 zacheiss Exp $
+/* $Id: mr_server.h,v 1.66 2008-05-19 20:21:56 zacheiss Exp $
  *
  * Copyright (C) 1987-1998 by the Massachusetts Institute of Technology
  * For copying and distribution information, please see the file
@@ -45,6 +45,12 @@
   int hslen;			/* Length of data in hsbuf */
 } client;
 
+struct mxentry
+{
+  char *name;
+  int pref;
+};
+
 extern char krb_realm[REALM_SZ];
 
 /* max length of query argument allowed */
@@ -156,6 +162,8 @@
 int access_zephyr(struct query *q, char *argv[], client *cl);
 int access_container(struct query *q, char *argv[], client *cl);
 int access_update_user(struct query *q, char *argv[], client *cl);
+int check_mail_string(char *mailstring);
+struct mxentry *getmxrecords(const char *);
 
 /* prototypes from qfollow.pc */
 int followup_fix_modby(struct query *q, struct save_queue *sq,
--- debathena-moira-4.0.0+cvs20080304.orig/server/qaccess.pc
+++ debathena-moira-4.0.0+cvs20080304/server/qaccess.pc
@@ -1,4 +1,4 @@
-/* $Id: qaccess.pc,v 2.32 2008-01-03 19:48:08 zacheiss Exp $
+/* $Id: qaccess.pc,v 2.34 2008-05-19 20:21:56 zacheiss Exp $
  *
  * Check access to queries
  *
@@ -14,10 +14,14 @@
 
 #include <ctype.h>
 #include <stdlib.h>
+#include <netdb.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
 
 EXEC SQL INCLUDE sqlca;
 
-RCSID("$Header: /afs/athena.mit.edu/astaff/project/moiradev/repository/moira/server/qaccess.pc,v 2.32 2008-01-03 19:48:08 zacheiss Exp $");
+RCSID("$Header: /afs/athena.mit.edu/astaff/project/moiradev/repository/moira/server/qaccess.pc,v 2.34 2008-05-19 20:21:56 zacheiss Exp $");
 
 extern char *whoami;
 extern int dbms_errno, mr_errcode;
@@ -140,6 +144,7 @@
   EXEC SQL BEGIN DECLARE SECTION;
   int id;
   EXEC SQL END DECLARE SECTION;
+  int status;
 
   if (!strcmp(argv[1], "IMAP"))
       {
@@ -149,6 +154,17 @@
 	if (cl->users_id != id)
 	  return MR_PERM;
       }
+
+  /* Non-query owners can't forward mail to a POSTOFFICE or MAILHUB server,
+   * nor to a nonresolving domain.
+   */
+  if (!strcmp(argv[1], "SMTP") || !strcmp(argv[1], "SPLIT"))
+    {
+      status = check_mail_string(argv[2]);
+      if (status)
+	return status;
+    }
+
   if (cl->users_id != *(int *)argv[0])
     return MR_PERM;
   else
@@ -178,6 +194,7 @@
   char member_acl_type[LIST_ACL_TYPE_SIZE], memacl_type[LIST_ACL_TYPE_SIZE];
   EXEC SQL END DECLARE SECTION;
   int status, cnt;
+  char *buf;
 
   list_id = *(int *)argv[0];
   member_id = *(int *)argv[2];
@@ -245,6 +262,26 @@
 	}
     }
 
+  /* Don't allow non-query owners to add STRINGs to lists if they end
+   * in a domain that's MIT.EDU or one of the hosts that provide the
+   * MAILHUB or POSTOFFICE services.
+   */
+  if (!strcmp(q->shortname, "amtl") || !strcmp(q->shortname, "atml"))
+    {
+      if (!strcmp("STRING", argv[1]))
+	{
+	  buf = malloc(0);
+	  status = id_to_name(*(int *)argv[2], STRINGS_TABLE, &buf);
+	  if (status)
+	    return status;
+
+	  status = check_mail_string(buf);
+	  free(buf);
+	  if (status)
+	    return status;
+	}
+    }
+
   /* check for client in access control list and return success right 
    * away if it's there. */
   if (find_member(acl_type, acl_id, cl))
@@ -780,3 +817,172 @@
   /* Otherwise fail. */
   return MR_PERM;
 }
+
+int check_mail_string(char *mailstring)
+{
+  EXEC SQL BEGIN DECLARE SECTION;
+  char mname[MACHINE_NAME_SIZE];
+  EXEC SQL END DECLARE SECTION;
+  char *p, *host, *hostdomain;
+  struct hostent *hp;
+  struct mxentry *mxrecords = NULL;
+  int index;
+
+  p = strchr(mailstring, '@');
+  if (p)
+    {
+      host = strdup(++p);
+      
+      /* Replace .LOCAL at end of host with .MIT.EDU if needed. */
+      hostdomain = strrchr(host, '.');
+      if (hostdomain && !strcasecmp(hostdomain, ".LOCAL"))
+	{
+	  index = hostdomain - host;
+	  host[index] = '\0';
+	  host = realloc(host, strlen(host) + strlen(".MIT.EDU") + 1);
+	  strcat(host, ".MIT.EDU");
+	}
+      
+      hp = gethostbyname(host);
+      if (hp)
+	{
+	  host = realloc(host, strlen(hp->h_name) + 1);
+	  if (host)
+	    strcpy(host, hp->h_name);
+	}
+      else
+	{
+	  /* Possibly a host with no A record but MX records.  Check. */
+	  mxrecords = getmxrecords(host);
+	  if (!mxrecords)
+	    return MR_BAD_MAIL_STRING;
+	  else
+	    return MR_SUCCESS;
+	}
+      
+      if (!strcasecmp(host, "MIT.EDU"))
+	{
+	  free(host);
+	  return MR_BAD_MAIL_STRING;
+	}
+      
+      EXEC SQL DECLARE csr_listmem CURSOR FOR
+	SELECT UNIQUE m.name FROM machine m, serverhosts sh
+	WHERE m.mach_id = sh.mach_id
+	AND (sh.service = 'MAILHUB' or sh.service = 'POSTOFFICE');
+      if (dbms_errno)
+	{
+	  free(host);
+	  return mr_errcode;
+	}
+      EXEC SQL OPEN csr_listmem;
+      if (dbms_errno)
+	{
+	  free(host);
+	  return mr_errcode;
+	}
+      while (1)
+	{
+	  EXEC SQL FETCH csr_listmem INTO :mname;
+	  if (sqlca.sqlcode)
+	    break;
+	  
+	  if (!strcasecmp(host, strtrim(mname)))
+	    {
+	      free(host);
+	      return MR_BAD_MAIL_STRING;
+	    }
+	}
+      free(host);
+    }
+
+  return MR_SUCCESS;
+}
+
+/*
+ * This ought to be in the bind library.  It's adapted from sendmail.
+ */
+
+/*
+ * These are defined in RFC833. Some bind interface headers don't declare them.
+ * Ghod help us if they're ever actually incompatible with what's in 
+ * the arpa/nameser.h header.
+ */
+#ifndef PACKETSZ
+#define PACKETSZ	512		/* maximum packet size */
+#endif
+#ifndef HFIXEDSZ
+#define	HFIXEDSZ	12		/* #/bytes of fixed data in header */
+#endif
+#ifndef INT32SZ
+#define	INT32SZ		4		/* for systems without 32-bit ints */
+#endif
+#ifndef INT16SZ
+#define	INT16SZ		2		/* for systems without 16-bit ints */
+#endif
+
+/* minimum possible size of MX record in packet */
+#define MIN_MX_SIZE	8	/* corresp to "a.com 0" w/ terminating space */
+
+struct mxentry *getmxrecords(const char *name)
+{
+  char answer[PACKETSZ], *eom, *cp, *bp;
+  int n, ancount, qdcount, buflen, type, pref, ind;
+  static struct mxentry pmx[(PACKETSZ - HFIXEDSZ) / MIN_MX_SIZE];
+  static char MXHostBuf[PACKETSZ - HFIXEDSZ]; 
+  HEADER *hp;
+  
+  pmx->name = (char *)NULL;
+  pmx->pref = -1;
+  n = res_search(name, C_IN,T_MX, (unsigned char *)&answer, sizeof(answer));
+  if (n == -1)
+    return((struct mxentry *)NULL);
+  if ((size_t)n > sizeof(answer))
+    n = sizeof(answer);    	
+  
+  hp = (HEADER *)&answer;
+  cp = answer + HFIXEDSZ;
+  eom = answer + n;
+  h_errno = 0;
+  for (qdcount = ntohs(hp->qdcount); qdcount--; cp += n + QFIXEDSZ)
+    if ((n = dn_skipname((unsigned char *)cp, (unsigned char *)eom)) < 0)
+      return((struct mxentry *)NULL);
+  buflen = sizeof(MXHostBuf) - 1;
+  bp = MXHostBuf;
+  ind = 0;
+  ancount = ntohs(hp->ancount);
+  while (--ancount >= 0 && cp < eom)
+    {
+      if ((n = dn_expand((unsigned char *)answer, (unsigned char *)eom,
+			 (unsigned char *)cp, bp, buflen)) < 0)
+	break;
+      cp += n;
+      GETSHORT(type, cp);
+      cp += INT16SZ + INT32SZ;
+      GETSHORT(n, cp);
+      if (type != T_MX)
+	{
+	  cp += n;
+	  continue;
+	}
+      GETSHORT(pref, cp);
+      if ((n = dn_expand((unsigned char *)answer, (unsigned char *)eom,
+			 (unsigned char *)cp, bp, buflen)) < 0)
+	break;
+      cp += n;
+      
+      pmx[ind].name = bp;
+      pmx[ind].pref = pref;
+      ++ind;
+      
+      n = strlen((const char *)bp);
+      bp += n;
+      *bp++ = '\0';
+      
+      buflen -= n + 1;
+    }
+  
+  pmx[ind].name = (char *)NULL;
+  pmx[ind].pref = -1;
+  return(pmx);
+}
--- debathena-moira-4.0.0+cvs20080304.orig/server/qsupport.pc
+++ debathena-moira-4.0.0+cvs20080304/server/qsupport.pc
@@ -1,4 +1,4 @@
-/* $Id: qsupport.pc,v 2.51 2007-11-29 18:09:10 zacheiss Exp $
+/* $Id: qsupport.pc,v 2.52 2008-04-25 17:01:32 zacheiss Exp $
  *
  * Special query routines
  *
@@ -18,7 +18,7 @@
 
 EXEC SQL INCLUDE sqlca;
 
-RCSID("$Header: /afs/athena.mit.edu/astaff/project/moiradev/repository/moira/server/qsupport.pc,v 2.51 2007-11-29 18:09:10 zacheiss Exp $");
+RCSID("$Header: /afs/athena.mit.edu/astaff/project/moiradev/repository/moira/server/qsupport.pc,v 2.52 2008-04-25 17:01:32 zacheiss Exp $");
 
 extern char *whoami, *table_name[];
 extern int dbms_errno, mr_errcode;
@@ -169,7 +169,7 @@
  * how many different ancestors a member is allowed to have.
  */
 
-#define MAXLISTDEPTH	2048
+#define MAXLISTDEPTH	3072
 
 int add_member_to_list(struct query *q, char **argv, client *cl)
 {
--- debathena-moira-4.0.0+cvs20080304.orig/server/queries2.c
+++ debathena-moira-4.0.0+cvs20080304/server/queries2.c
@@ -1,4 +1,4 @@
-/* $Id: queries2.c,v 2.105 2007-11-29 22:41:52 zacheiss Exp $
+/* $Id: queries2.c,v 2.106 2008-04-23 21:07:58 zacheiss Exp $
  *
  * This file defines the query dispatch table
  *
@@ -648,7 +648,7 @@
   "login",
   "newlogin", "unix_uid", "shell", "winconsoleshell", "last", "first",
   "middle", "status", "clearid", "class", "comments", "signature", "secure",
-  "winhomedir", "winprofiledir, sponsor_type, sponsor_name", "expiration",
+  "winhomedir", "winprofiledir", "sponsor_type", "sponsor_name", "expiration",
 };
 
 static struct valobj uuac2_valobj[] = {
--- debathena-moira-4.0.0+cvs20080304.orig/debian/compat
+++ debathena-moira-4.0.0+cvs20080304/debian/compat
@@ -0,0 +1 @@
+4
--- debathena-moira-4.0.0+cvs20080304.orig/debian/control.in
+++ debathena-moira-4.0.0+cvs20080304/debian/control.in
@@ -0,0 +1,28 @@
+Source: debathena-moira
+Section: debathena/net
+Priority: extra
+Maintainer: Debian-Athena Project <debathena@mit.edu>
+Build-Depends: @cdbs@, comerr-dev, libkrb5-dev, libhesiod-dev, libzephyr-dev, libzephyr3-krb, libreadline-dev, libncurses-dev
+Standards-Version: 3.7.2
+
+Package: debathena-moira-clients
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Description: Clients for the Moira database
+ Moira is the Athena Service Management system.  It serves as the 
+ central repository for information about users, groups hosts, print 
+ queues, and several other aspects of the Athena environment.
+ .
+ This package contains clients such as moira, stella, blanche, etc.
+
+Package: debathena-libmoira-dev
+Section: debathena/libdevel
+Architecture: any
+Provides: libmoira-dev
+Depends: ${shlibs:Depends}, ${misc:Depends}, comerr-dev, libkrb5-dev, libhesiod-dev, libzephyr-dev, libzephyr3-krb
+Description: Development files for Moira library
+ Moira is the Athena Service Management system.  It serves as the 
+ central repository for information about users, groups hosts, print 
+ queues, and several other aspects of the Athena environment.
+ .
+ This package contains headers and static libraries for development.
--- debathena-moira-4.0.0+cvs20080304.orig/debian/copyright
+++ debathena-moira-4.0.0+cvs20080304/debian/copyright
@@ -0,0 +1,20 @@
+The Moria source code was obtained from the Moira CVS repository at 
+/afs/athena.mit.edu/astaff/project/moiradev, and is licensed as follows:
+
+  Copyright (C) 1987-1998 by the Massachusetts Institute of Technology
+  
+  Permission to use, copy, modify, and distribute this
+  software and its documentation for any purpose and without
+  fee is hereby granted, provided that the above copyright
+  notice appear in all copies and that both that copyright
+  notice and this permission notice appear in supporting
+  documentation, and that the name of M.I.T. not be used in
+  advertising or publicity pertaining to distribution of the
+  software without specific, written prior permission.
+  M.I.T. makes no representations about the suitability of
+  this software for any purpose.  It is provided "as is"
+  without express or implied warranty.
+
+This Debian package was created as part of the Debian-Athena Project
+<http://web.mit.edu/debathena/www/> of the MIT Student Information
+Processing Board, and is released to the public domain.
--- debathena-moira-4.0.0+cvs20080304.orig/debian/control
+++ debathena-moira-4.0.0+cvs20080304/debian/control
@@ -0,0 +1,28 @@
+Source: debathena-moira
+Section: debathena/net
+Priority: extra
+Maintainer: Debian-Athena Project <debathena@mit.edu>
+Build-Depends: cdbs (>= 0.4.23-1.1), autotools-dev, debhelper (>= 4.2.0), quilt, patchutils (>= 0.2.25), cdbs (>= 0.4.27-1), comerr-dev, libkrb5-dev, libhesiod-dev, libzephyr-dev, libzephyr3-krb, libreadline-dev, libncurses-dev
+Standards-Version: 3.7.2
+
+Package: debathena-moira-clients
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Description: Clients for the Moira database
+ Moira is the Athena Service Management system.  It serves as the 
+ central repository for information about users, groups hosts, print 
+ queues, and several other aspects of the Athena environment.
+ .
+ This package contains clients such as moira, stella, blanche, etc.
+
+Package: debathena-libmoira-dev
+Section: debathena/libdevel
+Architecture: any
+Provides: libmoira-dev
+Depends: ${shlibs:Depends}, ${misc:Depends}, comerr-dev, libkrb5-dev, libhesiod-dev, libzephyr-dev, libzephyr3-krb
+Description: Development files for Moira library
+ Moira is the Athena Service Management system.  It serves as the 
+ central repository for information about users, groups hosts, print 
+ queues, and several other aspects of the Athena environment.
+ .
+ This package contains headers and static libraries for development.
--- debathena-moira-4.0.0+cvs20080304.orig/debian/rules
+++ debathena-moira-4.0.0+cvs20080304/debian/rules
@@ -0,0 +1,20 @@
+#!/usr/bin/make -f
+
+DEB_AUTO_UPDATE_DEBIAN_CONTROL = 1
+include /usr/share/cdbs/1/rules/debhelper.mk
+include /usr/share/cdbs/1/class/autotools.mk
+include /usr/share/cdbs/1/rules/patchsys-quilt.mk
+
+DEB_CONFIGURE_EXTRA_FLAGS += --with-krb4=$(shell krb5-config --prefix krb4) --with-krb5 --with-hesiod --with-zephyr --with-com_err=/usr --without-oracle --without-afs
+DEB_DH_INSTALL_SOURCEDIR = $(DEB_DESTDIR)
+
+common-install-impl::
+	mv $(DEB_DESTDIR)/usr/bin/chfn $(DEB_DESTDIR)/usr/bin/chfn.moira
+	mv $(DEB_DESTDIR)/usr/bin/chsh $(DEB_DESTDIR)/usr/bin/chsh.moira
+	mv $(DEB_DESTDIR)/usr/share/man/man1/chsh.1 \
+		$(DEB_DESTDIR)/usr/share/man/man1/chsh.moira.1
+	mv $(DEB_DESTDIR)/usr/share/man/man1/chfn.1 \
+		$(DEB_DESTDIR)/usr/share/man/man1/chfn.moira.1
+
+clean::
+	rm -f util/rsaref/Makefile
--- debathena-moira-4.0.0+cvs20080304.orig/debian/patches/series
+++ debathena-moira-4.0.0+cvs20080304/debian/patches/series
@@ -0,0 +1 @@
+moira-build-destdir.patch
--- debathena-moira-4.0.0+cvs20080304.orig/debian/patches/moira-build-destdir.patch
+++ debathena-moira-4.0.0+cvs20080304/debian/patches/moira-build-destdir.patch
@@ -0,0 +1,218 @@
+Index: debathena-moira-4.0.0+cvs20070129/Makefile.in
+===================================================================
+--- debathena-moira-4.0.0+cvs20070129.orig/Makefile.in	2007-02-14 01:59:19.000000000 -0500
++++ debathena-moira-4.0.0+cvs20070129/Makefile.in	2007-02-14 02:06:36.000000000 -0500
+@@ -35,11 +35,11 @@
+ 	@for d in $(SUBDIRS); do (echo "### Making $@ in $$d"; cd $$d; $(MAKE) $@) || exit 1; done
+ 
+ install:
+-	$(srcdir)/mkinstalldirs $(bindir) $(sbindir) $(mrbindir) $(mandir)
++	$(srcdir)/mkinstalldirs $(DESTDIR)$(bindir) $(DESTDIR)$(sbindir) $(DESTDIR)$(mandir)
+ 	@for d in $(SUBDIRS); do (echo "### Making $@ in $$d"; cd $$d; $(MAKE) $@) || exit 1; done
+ 
+ svrinstall:
+-	$(srcdir)/mkinstalldirs $(mrbindir)
++	$(srcdir)/mkinstalldirs $(DESTDIR)$(mrbindir)
+ 	@for d in $(SVRDIRS); do (echo "### Making install in $$d"; cd $$d; $(MAKE) install) || exit 1; done
+ 
+ world: depend all
+Index: debathena-moira-4.0.0+cvs20070129/clients/addusr/Makefile.in
+===================================================================
+--- debathena-moira-4.0.0+cvs20070129.orig/clients/addusr/Makefile.in	2007-02-14 01:59:19.000000000 -0500
++++ debathena-moira-4.0.0+cvs20070129/clients/addusr/Makefile.in	2007-02-14 01:59:59.000000000 -0500
+@@ -40,7 +40,7 @@
+ depend:
+ 
+ install: all
+-	$(INSTALL_PROGRAM) -m 755 addusr $(bindir)
++	$(INSTALL_PROGRAM) -m 755 addusr $(DESTDIR)$(bindir)
+ 
+ $(TARGET): $(OBJS) ../lib/libmrclient.a $(MR_LIBDEP)
+ 	$(CC) -o $@ $(LDFLAGS) $(OBJS) $(LIBS)
+Index: debathena-moira-4.0.0+cvs20070129/clients/blanche/Makefile.in
+===================================================================
+--- debathena-moira-4.0.0+cvs20070129.orig/clients/blanche/Makefile.in	2007-02-14 01:59:20.000000000 -0500
++++ debathena-moira-4.0.0+cvs20070129/clients/blanche/Makefile.in	2007-02-14 01:59:59.000000000 -0500
+@@ -40,7 +40,7 @@
+ depend:
+ 
+ install: all
+-	$(INSTALL_PROGRAM) blanche $(bindir)
++	$(INSTALL_PROGRAM) blanche $(DESTDIR)$(bindir)
+ 
+ $(TARGET): $(OBJS) ../lib/libmrclient.a $(MR_LIBDEP)
+ 	$(CC) -o $@ $(LDFLAGS) $(OBJS) $(LIBS)
+Index: debathena-moira-4.0.0+cvs20070129/clients/chfn/Makefile.in
+===================================================================
+--- debathena-moira-4.0.0+cvs20070129.orig/clients/chfn/Makefile.in	2007-02-14 01:59:20.000000000 -0500
++++ debathena-moira-4.0.0+cvs20070129/clients/chfn/Makefile.in	2007-02-14 01:59:59.000000000 -0500
+@@ -40,7 +40,7 @@
+ depend:
+ 
+ install: all
+-	$(INSTALL_PROGRAM) $(TARGET) $(bindir)
++	$(INSTALL_PROGRAM) $(TARGET) $(DESTDIR)$(bindir)
+ 
+ $(TARGET): $(OBJS) ../lib/libmrclient.a $(MR_LIBDEP)
+ 	$(CC) -o $@ $(LDFLAGS) $@.o $(LIBS)
+Index: debathena-moira-4.0.0+cvs20070129/clients/chpobox/Makefile.in
+===================================================================
+--- debathena-moira-4.0.0+cvs20070129.orig/clients/chpobox/Makefile.in	2007-02-14 01:59:20.000000000 -0500
++++ debathena-moira-4.0.0+cvs20070129/clients/chpobox/Makefile.in	2007-02-14 01:59:59.000000000 -0500
+@@ -40,7 +40,7 @@
+ depend:
+ 
+ install: all
+-	$(INSTALL_PROGRAM) $(TARGET) $(bindir)
++	$(INSTALL_PROGRAM) $(TARGET) $(DESTDIR)$(bindir)
+ 
+ $(TARGET): $(OBJS) ../lib/libmrclient.a $(MR_LIBDEP)
+ 	$(CC) -o $@ $(LDFLAGS) $@.o $(LIBS)
+Index: debathena-moira-4.0.0+cvs20070129/clients/chsh/Makefile.in
+===================================================================
+--- debathena-moira-4.0.0+cvs20070129.orig/clients/chsh/Makefile.in	2007-02-14 01:59:20.000000000 -0500
++++ debathena-moira-4.0.0+cvs20070129/clients/chsh/Makefile.in	2007-02-14 01:59:59.000000000 -0500
+@@ -40,7 +40,7 @@
+ depend:
+ 
+ install: all
+-	$(INSTALL_PROGRAM) $(TARGET) $(bindir)
++	$(INSTALL_PROGRAM) $(TARGET) $(DESTDIR)$(bindir)
+ 
+ $(TARGET): $(OBJS) ../lib/libmrclient.a $(MR_LIBDEP)
+ 	$(CC) -o $@ $(LDFLAGS) $@.o $(LIBS)
+Index: debathena-moira-4.0.0+cvs20070129/clients/mailmaint/Makefile.in
+===================================================================
+--- debathena-moira-4.0.0+cvs20070129.orig/clients/mailmaint/Makefile.in	2007-02-14 01:59:20.000000000 -0500
++++ debathena-moira-4.0.0+cvs20070129/clients/mailmaint/Makefile.in	2007-02-14 01:59:59.000000000 -0500
+@@ -40,7 +40,7 @@
+ depend:
+ 
+ install: all
+-	$(INSTALL_PROGRAM) mailmaint $(bindir)
++	$(INSTALL_PROGRAM) mailmaint $(DESTDIR)$(bindir)
+ 
+ $(TARGET): $(OBJS) ../lib/libmrclient.a $(MR_LIBDEP)
+ 	$(CC) -o $@ $(LDFLAGS) $(OBJS) $(LIBS)
+Index: debathena-moira-4.0.0+cvs20070129/clients/mitch/Makefile.in
+===================================================================
+--- debathena-moira-4.0.0+cvs20070129.orig/clients/mitch/Makefile.in	2007-02-14 01:59:20.000000000 -0500
++++ debathena-moira-4.0.0+cvs20070129/clients/mitch/Makefile.in	2007-02-14 01:59:59.000000000 -0500
+@@ -40,7 +40,7 @@
+ depend:
+ 
+ install: all
+-	$(INSTALL_PROGRAM) mitch $(bindir)
++	$(INSTALL_PROGRAM) mitch $(DESTDIR)$(bindir)
+ 
+ $(TARGET): $(OBJS) ../lib/libmrclient.a $(MR_LIBDEP)
+ 	$(CC) -o $@ $(LDFLAGS) $(OBJS) $(LIBS)
+Index: debathena-moira-4.0.0+cvs20070129/clients/moira/Makefile.in
+===================================================================
+--- debathena-moira-4.0.0+cvs20070129.orig/clients/moira/Makefile.in	2007-02-14 01:59:20.000000000 -0500
++++ debathena-moira-4.0.0+cvs20070129/clients/moira/Makefile.in	2007-02-14 02:07:47.000000000 -0500
+@@ -44,14 +44,14 @@
+ depend:
+ 
+ install: all
+-	$(INSTALL_PROGRAM) namespace $(bindir)
+-	$(INSTALL_PROGRAM) moira $(bindir)
+-	rm -f $(bindir)/listmaint	
+-	ln -s moira $(bindir)/listmaint
+-	rm -f $(bindir)/dcmmaint
+-	ln -s moira $(bindir)/dcmmaint
+-	rm -f $(bindir)/usermaint
+-	ln -s moira $(bindir)/usermaint
++	$(INSTALL_PROGRAM) namespace $(DESTDIR)$(bindir)
++	$(INSTALL_PROGRAM) moira $(DESTDIR)$(bindir)
++	rm -f $(DESTDIR)$(bindir)/listmaint
++	ln -s moira $(DESTDIR)$(bindir)/listmaint
++	rm -f $(DESTDIR)$(bindir)/dcmmaint
++	ln -s moira $(DESTDIR)$(bindir)/dcmmaint
++	rm -f $(DESTDIR)$(bindir)/usermaint
++	ln -s moira $(DESTDIR)$(bindir)/usermaint
+ 
+ moira: $(MOBJS) ../lib/libmrclient.a $(MR_LIBDEP)
+ 	$(CC) -o $@ $(LDFLAGS) $(MOBJS) $(LIBS)
+Index: debathena-moira-4.0.0+cvs20070129/clients/mrcheck/Makefile.in
+===================================================================
+--- debathena-moira-4.0.0+cvs20070129.orig/clients/mrcheck/Makefile.in	2007-02-14 01:59:20.000000000 -0500
++++ debathena-moira-4.0.0+cvs20070129/clients/mrcheck/Makefile.in	2007-02-14 01:59:59.000000000 -0500
+@@ -40,7 +40,7 @@
+ depend:
+ 
+ install: all
+-	$(INSTALL_PROGRAM) mrcheck $(bindir)
++	$(INSTALL_PROGRAM) mrcheck $(DESTDIR)$(bindir)
+ 
+ $(TARGET): $(OBJS) ../lib/libmrclient.a $(MR_LIBDEP)
+ 	$(CC) -o $@ $(LDFLAGS) $(OBJS) $(LIBS)
+Index: debathena-moira-4.0.0+cvs20070129/clients/mrtest/Makefile.in
+===================================================================
+--- debathena-moira-4.0.0+cvs20070129.orig/clients/mrtest/Makefile.in	2007-02-14 01:59:21.000000000 -0500
++++ debathena-moira-4.0.0+cvs20070129/clients/mrtest/Makefile.in	2007-02-14 01:59:59.000000000 -0500
+@@ -40,7 +40,7 @@
+ depend:
+ 
+ install: all
+-	$(INSTALL_PROGRAM) mrtest $(bindir)
++	$(INSTALL_PROGRAM) mrtest $(DESTDIR)$(bindir)
+ 
+ $(TARGET): $(OBJS) ../lib/libmrclient.a $(MR_LIBDEP)
+ 	$(CC) -o $@ $(LDFLAGS) $(OBJS) $(LIBS)
+Index: debathena-moira-4.0.0+cvs20070129/clients/stanley/Makefile.in
+===================================================================
+--- debathena-moira-4.0.0+cvs20070129.orig/clients/stanley/Makefile.in	2007-02-14 01:59:21.000000000 -0500
++++ debathena-moira-4.0.0+cvs20070129/clients/stanley/Makefile.in	2007-02-14 01:59:59.000000000 -0500
+@@ -40,7 +40,7 @@
+ depend:
+ 
+ install: all
+-	$(INSTALL_PROGRAM) stanley $(bindir)
++	$(INSTALL_PROGRAM) stanley $(DESTDIR)$(bindir)
+ 
+ $(TARGET): $(OBJS) ../lib/libmrclient.a $(MR_LIBDEP)
+ 	$(CC) -o $@ $(LDFLAGS) $(OBJS) $(LIBS)
+Index: debathena-moira-4.0.0+cvs20070129/clients/stella/Makefile.in
+===================================================================
+--- debathena-moira-4.0.0+cvs20070129.orig/clients/stella/Makefile.in	2007-02-14 01:59:21.000000000 -0500
++++ debathena-moira-4.0.0+cvs20070129/clients/stella/Makefile.in	2007-02-14 02:00:00.000000000 -0500
+@@ -40,7 +40,7 @@
+ depend:
+ 
+ install: all
+-	$(INSTALL_PROGRAM) stella $(bindir)
++	$(INSTALL_PROGRAM) stella $(DESTDIR)$(bindir)
+ 
+ $(TARGET): $(OBJS) ../lib/libmrclient.a $(MR_LIBDEP)
+ 	$(CC) -o $@ $(LDFLAGS) $(OBJS) $(LIBS)
+Index: debathena-moira-4.0.0+cvs20070129/man/Makefile.in
+===================================================================
+--- debathena-moira-4.0.0+cvs20070129.orig/man/Makefile.in	2007-02-14 01:59:21.000000000 -0500
++++ debathena-moira-4.0.0+cvs20070129/man/Makefile.in	2007-02-14 02:00:00.000000000 -0500
+@@ -32,6 +32,7 @@
+ depend:
+ 
+ install:
+-	for m in $(MAN1); do $(INSTALL_DATA) $(srcdir)/$$m $(mandir)/man1; done
+-	for m in $(MAN3); do $(INSTALL_DATA) $(srcdir)/$$m $(mandir)/man3; done
+-	for m in $(MAN8); do $(INSTALL_DATA) $(srcdir)/$$m $(mandir)/man8; done
++	$(srcdir)/../mkinstalldirs $(DESTDIR)$(mandir)/man1 $(DESTDIR)$(mandir)/man3 $(DESTDIR)$(mandir)/man8
++	for m in $(MAN1); do $(INSTALL_DATA) $(srcdir)/$$m $(DESTDIR)$(mandir)/man1; done
++	for m in $(MAN3); do $(INSTALL_DATA) $(srcdir)/$$m $(DESTDIR)$(mandir)/man3; done
++	for m in $(MAN8); do $(INSTALL_DATA) $(srcdir)/$$m $(DESTDIR)$(mandir)/man8; done
+Index: debathena-moira-4.0.0+cvs20070129/update/Makefile.in
+===================================================================
+--- debathena-moira-4.0.0+cvs20070129.orig/update/Makefile.in	2007-02-14 01:59:21.000000000 -0500
++++ debathena-moira-4.0.0+cvs20070129/update/Makefile.in	2007-02-14 02:00:00.000000000 -0500
+@@ -43,8 +43,8 @@
+ depend:
+ 
+ install: all
+-	$(INSTALL_PROGRAM) update_test $(bindir)
+-	$(INSTALL_PROGRAM) update_server $(sbindir)
++	$(INSTALL_PROGRAM) update_test $(DESTDIR)$(bindir)
++	$(INSTALL_PROGRAM) update_server $(DESTDIR)$(sbindir)
+ 
+ update_test: $(COBJS) $(MR_LIBDEP)
+ 	$(CC) -o $@ $(LDFLAGS) $(COBJS) $(LIBS)
--- debathena-moira-4.0.0+cvs20080304.orig/debian/changelog
+++ debathena-moira-4.0.0+cvs20080304/debian/changelog
@@ -0,0 +1,38 @@
+debathena-moira (4.0.0+cvs20080304-0debathena1) unstable; urgency=low
+
+  * New CVS snapshot to fix chsh.
+
+ -- Anders Kaseorg <andersk@mit.edu>  Tue, 04 Mar 2008 15:50:31 -0500
+
+debathena-moira (4.0.0+cvs20080301-0debathena1) unstable; urgency=low
+
+  * New CVS snapshot.
+  * Remove mrtest segfault patch from last release (fixed in upstream)
+
+ -- Tim Abbott <tabbott@mit.edu>  Sat,  1 Mar 2008 18:51:40 -0500
+
+debathena-moira (4.0.0+cvs20070817-0debathena1) unstable; urgency=low
+
+  * New CVS snapshot.
+  * Patch an mrtest segfault with too many command line arguments.
+
+ -- Anders Kaseorg <andersk@mit.edu>  Fri, 24 Aug 2007 19:53:49 -0400
+
+debathena-moira (4.0.0+cvs20070129-0debathena3) unstable; urgency=low
+
+  * Move chsh.debathena to chsh.moira and chfn.debathena to chfn.moira.
+
+ -- Anders Kaseorg <andersk@mit.edu>  Mon, 06 Aug 2007 03:17:10 -0400
+
+debathena-moira (4.0.0+cvs20070129-0debathena2) unstable; urgency=low
+
+  * Add missing build dependencies to libmoira-dev.
+  * Section: debathena/net.
+
+ -- Anders Kaseorg <andersk@mit.edu>  Tue, 17 Jul 2007 06:34:07 -0400
+
+debathena-moira (4.0.0+cvs20070129-0debathena1) unstable; urgency=low
+
+  * Initial release.
+
+ -- Anders Kaseorg <andersk@mit.edu>  Wed, 14 Feb 2007 00:53:24 -0500
--- debathena-moira-4.0.0+cvs20080304.orig/debian/debathena-moira-clients.install
+++ debathena-moira-4.0.0+cvs20080304/debian/debathena-moira-clients.install
@@ -0,0 +1,18 @@
+usr/bin/addusr
+usr/bin/blanche
+usr/bin/chfn.moira
+usr/bin/chpobox
+usr/bin/chsh.moira
+usr/bin/mitch
+usr/bin/namespace
+usr/bin/moira
+usr/bin/mrcheck
+usr/bin/mrtest
+usr/bin/stanley
+usr/bin/stella
+usr/bin/mailmaint
+usr/bin/listmaint
+usr/bin/dcmmaint
+usr/bin/usermaint
+usr/share/man/man1/*
+usr/share/man/man8/mrtest.8
--- debathena-moira-4.0.0+cvs20080304.orig/debian/debathena-libmoira-dev.install
+++ debathena-moira-4.0.0+cvs20080304/debian/debathena-libmoira-dev.install
@@ -0,0 +1,6 @@
+usr/share/man/man3/*
+include/moira.h usr/include/moira
+lib/mr_et.h usr/include/moira
+lib/krb_et.h usr/include/moira
+lib/ureg_err.h usr/include/moira
+lib/libmoira.a usr/lib
