calendarserver (2.4.dfsg-6) debian-dir only changes

Summary

 debian/NEWS                             |    7 
 debian/README.Debian                    |  123 ++++++
 debian/README.source                    |   57 ++
 debian/TODO                             |    2 
 debian/calendarserver-doc-api.docs      |    1 
 debian/calendarserver.TODO              |    2 
 debian/calendarserver.caldav.pam        |    6 
 debian/calendarserver.default           |    8 
 debian/calendarserver.dirs              |    4 
 debian/calendarserver.docs              |    1 
 debian/calendarserver.examples          |    5 
 debian/calendarserver.init.d            |   97 ++++
 debian/calendarserver.manpages          |    4 
 debian/calendarserver.postinst          |   86 ++++
 debian/calendarserver.preinst           |   12 
 debian/changelog                        |  322 ++++++++++++++++
 debian/compat                           |    1 
 debian/control                          |   24 +
 debian/copyright                        |   41 ++
 debian/patches/ldapdirectory.patch      |  634 ++++++++++++++++++++++++++++++++
 debian/patches/linux-xattr-fix.patch    |  182 +++++++++
 debian/patches/nssdirectory.patch       |  316 +++++++++++++++
 debian/patches/paths.diff               |  175 ++++++++
 debian/patches/secure-python-path.patch |   64 +++
 debian/patches/series                   |    5 
 debian/pycompat                         |    1 
 debian/pyversions                       |    1 
 debian/rules                            |   30 +
 debian/upgrade-nss-data-directories.py  |  159 ++++++++
 29 files changed, 2370 insertions(+)

    
download this patch

Patch contents

--- calendarserver-2.4.dfsg.orig/debian/calendarserver-doc-api.docs
+++ calendarserver-2.4.dfsg/debian/calendarserver-doc-api.docs
@@ -0,0 +1 @@
+#doc/apidocs
--- calendarserver-2.4.dfsg.orig/debian/calendarserver.manpages
+++ calendarserver-2.4.dfsg/debian/calendarserver.manpages
@@ -0,0 +1,4 @@
+doc/caldavd.8
+doc/caladmin.8
+doc/calendarserver_export.8
+doc/calendarserver_manage_principals.8
--- calendarserver-2.4.dfsg.orig/debian/copyright
+++ calendarserver-2.4.dfsg/debian/copyright
@@ -0,0 +1,41 @@
+This package was debianized by Guido Guenther <agx@sigxcpu.org> on
+Sun, 27 Aug 2006 19:53:15 +0200.
+
+It was downloaded from http://trac.calendarserver.org/browser/CalendarServer
+
+Upstream Author: Cyrus Daboo <cdaboo@apple.com>
+
+Copyright: 2006 Apple Computer, Inc. All rights reserved.
+
+License:
+
+You are free to distribute this software under the terms of the Apache License
+2.0. The full text of this license can be found in the file
+/usr/share/common-licenses/Apache-2.0.
+
+Except for bin/xattr which is:
+
+##
+# Copyright (c) 2007 Apple Inc.
+#
+# This is the MIT license.  This software may also be distributed under the
+# same terms as Python (the PSF license).
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+##
--- calendarserver-2.4.dfsg.orig/debian/calendarserver.postinst
+++ calendarserver-2.4.dfsg/debian/calendarserver.postinst
@@ -0,0 +1,86 @@
+#!/bin/sh
+# postinst script for calendarserver
+#
+# see: dh_installdeb(1)
+
+set -e
+
+# summary of how this script can be called:
+#        * <postinst> `configure' <most-recently-configured-version>
+#        * <old-postinst> `abort-upgrade' <new version>
+#        * <conflictor's-postinst> `abort-remove' `in-favour' <package>
+#          <new-version>
+#        * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
+#          <failed-install-package> <version> `removing'
+#          <conflicting-package> <version>
+# for details, see http://www.debian.org/doc/debian-policy/ or
+# the debian-policy package
+#
+
+case "$1" in
+    configure)
+    	if ! getent passwd caldavd >/dev/null 2>&1; then
+    	    adduser --system --home /var/spool/caldavd --no-create-home 	\
+                    --gecos "calendarserver daemon" --group --disabled-password	\
+                    caldavd
+	fi
+	    adduser caldavd ssl-cert
+
+	for dir in spool run log lib; do
+	    if [ ! -d /var/$dir/caldavd ]; then
+	        mkdir -p /var/$dir/caldavd
+	    fi
+	    if ! dpkg-statoverride --list /var/$dir/caldavd >/dev/null 2>&1; then
+	        chown caldavd: /var/$dir/caldavd
+	    fi
+        done
+
+	echo "Moving data from old DataRoot (/var/run/caldavd/) to new DataRoot (/var/lib/caldavd/) (See Debian Bug#611165 for more info)"
+	for x in calendaruserproxy.sqlite resourceinfo.sqlite mailgatewaytokens.sqlite tasks; do
+	    echo -n "Moving /var/run/caldavd/$x ... "
+	    if [ -e /var/run/caldavd/$x ]; then
+	        if [ ! -e /var/lib/caldavd/$x ]; then
+	            mv /var/run/caldavd/$x /var/lib/caldavd/$x
+	            echo "Done."
+	        else
+	            echo "Aborted as /var/lib/caldavd/$x already exists."
+	        fi
+	    else
+	        echo "Aborted as it does not exist."
+	    fi
+	done
+
+	for file in calendaruserproxy.sqlite resourceinfo.sqlite mailgatewaytokens.sqlite; do
+            if [ ! -f /var/lib/caldavd/$file ]; then
+                touch /var/lib/caldavd/$file
+            fi
+	    if ! dpkg-statoverride --list /var/lib/caldavd/$file >/dev/null 2>&1; then
+	        chown caldavd: /var/lib/caldavd/$file
+	        chmod 640 /var/lib/caldavd/$file
+	    fi
+        done
+
+	# Upgrade NSS users and groups data directories (See Debian Bug#610124)
+	if [ -f /etc/caldavd/caldavd.plist.upgrade.nss.tmp ]; then
+		python /usr/share/doc/calendarserver/scripts/upgrade-nss-data-directories.py
+		rm -f /etc/caldavd/caldavd.plist.upgrade.nss.tmp
+	fi
+    ;;
+    abort-upgrade|abort-remove|abort-deconfigure)
+
+    ;;
+
+    *)
+        echo "postinst called with unknown argument \`$1'" >&2
+        exit 1
+    ;;
+esac
+
+# dh_installdeb will replace this with shell code automatically
+# generated by other debhelper scripts.
+
+#DEBHELPER#
+
+exit 0
+
+
--- calendarserver-2.4.dfsg.orig/debian/calendarserver.dirs
+++ calendarserver-2.4.dfsg/debian/calendarserver.dirs
@@ -0,0 +1,4 @@
+/var/lib/caldavd
+/var/log/caldavd
+/var/run/caldavd
+/var/spool/caldavd
--- calendarserver-2.4.dfsg.orig/debian/TODO
+++ calendarserver-2.4.dfsg/debian/TODO
@@ -0,0 +1,2 @@
+* fix apidoc build
+* push pydirector patches upstream
--- calendarserver-2.4.dfsg.orig/debian/control
+++ calendarserver-2.4.dfsg/debian/control
@@ -0,0 +1,24 @@
+Source: calendarserver
+Section: python
+Priority: optional
+Maintainer: Rahul Amaram <amaramrahul@users.sourceforge.net>
+Build-Depends: cdbs (>= 0.4.43), debhelper (>= 5), quilt, python, python-central
+Standards-Version: 3.9.1
+Homepage: http://calendarserver.org
+XS-Python-Version: >= 2.5
+
+Package: calendarserver
+Architecture: all
+Depends: ${python:Depends}, ${misc:Depends}, python-plist,
+ python-kerberos (>= 1.1+svn4241), python-pysqlite2, python-openssl,
+ python-vobject (>= 0.8.1c), python-twisted-calendarserver (>= 8.2.0.svn27622),
+ python-dateutil (>= 1.2),
+ python-xattr,
+ ssl-cert, adduser, lsb-base (>= 3.0-10), memcached (>=1.2.6)
+Recommends: python-pydirector, python-ldap
+XB-Python-Version: ${python:Versions}
+Description: Apple's Calendar Server
+ Apple's Calendarserver is a standalone caldav server with:
+  * Basic or Kerberos Authentication
+  * support for shared calendars
+
--- calendarserver-2.4.dfsg.orig/debian/calendarserver.docs
+++ calendarserver-2.4.dfsg/debian/calendarserver.docs
@@ -0,0 +1 @@
+README
--- calendarserver-2.4.dfsg.orig/debian/calendarserver.preinst
+++ calendarserver-2.4.dfsg/debian/calendarserver.preinst
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+set -e
+
+# Backup configuration file for upgrading NSS users and groups data directories in postinst
+if [ \( "$1" = "install" -o "$1" = "upgrade" \) -a "`echo $2 | cut -d - -f 1`" = "1.2.dfsg" ]; then
+	if [ -f /etc/caldavd/caldavd.plist -a ! -e /etc/caldavd/caldavd.plist.upgrade.nss.tmp ]; then
+		cp -a /etc/caldavd/caldavd.plist /etc/caldavd/caldavd.plist.upgrade.nss.tmp
+	fi
+fi
+
+#DEBHELPER#
--- calendarserver-2.4.dfsg.orig/debian/changelog
+++ calendarserver-2.4.dfsg/debian/changelog
@@ -0,0 +1,322 @@
+calendarserver (2.4.dfsg-6) unstable; urgency=low
+
+  * Changed DataRoot from /var/run/caldavd/ to /var/lib/caldavd/
+    (Closes: Bug#611165)
+
+ -- Rahul Amaram <amaramrahul@users.sourceforge.net>  Mon, 31 Jan 2011 17:09:50 +0530
+
+calendarserver (2.4.dfsg-5) unstable; urgency=high
+
+  * Backing up configuration file in calendarserver.preinst was happening
+    only during upgrade. This has been modified to happen during install as
+    well where the configuration file had not been purged during the previous 
+    uninstallation.
+
+ -- Rahul Amaram <amaramrahul@users.sourceforge.net>  Wed, 19 Jan 2011 14:24:14 +0530
+
+calendarserver (2.4.dfsg-4) unstable; urgency=high
+
+  * Moved the code for upgrading data directories of NSS users and groups
+    into a separate file and executing this file from postinst as it cannot
+    be assumed that python would be configured when preinst is called 
+    (inspite of adding python to Pre-Depends)
+  * Moved ${python:Depends} and python-plist from Pre-Depends to Depends
+
+ -- Rahul Amaram <amaramrahul@users.sourceforge.net>  Fri, 31 Dec 2010 14:58:23 +0530
+
+calendarserver (2.4.dfsg-3) unstable; urgency=low
+
+  * Added calendarserver.preinst script for moving data directories of NSS users
+    and groups
+  * Moved ${python:Depends} from Depends to Pre-Depends. Added python-plist to
+    Pre-Depends.
+  * Added python-ldap as recommended package (Closes: #600799)
+  * Moved python-pydirector from suggested package to recommended package
+  * Added information about disabling of group calendaring in calendarserver 2.x
+    in NEWS (Closes: #600999)
+
+ -- Rahul Amaram <amaramrahul@users.sourceforge.net>  Fri, 17 Dec 2010 00:00:00 +0530
+
+calendarserver (2.4.dfsg-2.1) unstable; urgency=high
+
+  * Non-maintainer upload.
+  * Do not set PYTHONPATH env var, not needed (Closes: #605166, #605157)
+  * Prevent setup.py from automagically setting #PYTHONPATH in an insecure way
+
+ -- Dmitrijs Ledkovs <dmitrij.ledkov@ubuntu.com>  Fri, 03 Dec 2010 21:28:40 +0000
+
+calendarserver (2.4.dfsg-2) unstable; urgency=low
+
+  * Removed Uploaders field in debian/changelog
+  * Changed build dependency python-dev to python
+  * Updated standards version to 3.9.1
+  * $remote_fs dependency has been added in init.d
+  * Added NSS directory service backend
+  * Added sample configuration for LDAP directory backend
+  * Added PAM configuration file
+
+ -- Rahul Amaram <amaramrahul@users.sourceforge.net>  Wed, 25 Aug 2010 15:23:37 +0530
+
+calendarserver (2.4.dfsg-1) experimental; urgency=low
+
+  * New upstream release (Closes: #579610)
+  * add LDAP directory backend
+  * remove NSS directory backend (will be added soon)
+  * add patch for linux xattr fix. Related Calendarserver ticket:
+      http://trac.calendarserver.org/ticket/337
+
+ -- Rahul Amaram <rahul@amaram.name>  Wed, 28 Jul 2010 13:57:56 +0530
+
+calendarserver (1.2.dfsg-9) unstable; urgency=low
+
+  [ Guido Günther ]
+  * [e933bae] Orphan package
+  * [aa801ee] use lower case http in the principals name since this is
+    what iCal expects. clients don't break. (Closes: #514931) - thanks
+    to Arthur P Prokosch for pointing this out and testing that other
+  * [2de5e32] We need both principals in the servers's keytab. (Closes:
+    #514931)
+
+  [ Christoph Goehre ]
+  * [080f99a] remove package depends 'python-xml' python-xml was merged into
+    the python core package and removed from unstable on 16th August 2009
+
+ -- Guido Günther <agx@sigxcpu.org>  Sun, 16 May 2010 15:15:51 +0200
+
+calendarserver (1.2.dfsg-8) unstable; urgency=low
+
+  * [8b63fa5] fix basic auth via apache directoryService (Closes:
+    #503727) - thanks to Thomas Viehmann for the patch
+  * [a9f92f3] minor fix: tabs vs. spaces
+
+ -- Guido Günther <agx@sigxcpu.org>  Thu, 06 Nov 2008 09:57:56 +0100
+
+calendarserver (1.2.dfsg-7) experimental; urgency=low
+
+  * [972f1c3] add more info about the name service switch backend and
+    warn about ldap server search limits (Closes: #499963)
+  * [45cc01f] add Ticket207-2.patch fixes "Events more than 356 days
+    from creation are ignored" (Closes: #489188) - Patch by Peter Mogensen
+
+ -- Guido Guenther <agx@sigxcpu.org>  Thu, 02 Oct 2008 13:18:01 +0200
+
+calendarserver (1.2.dfsg-6) unstable; urgency=low
+
+  * [cf51d29] allow dh_installinit to start/stop the daemon
+  * [f2450f8] don't start calendarserver by default
+  * [67f428c] don't fail when trying to stop a not running daemon
+  * [b3386ab] bump standards version
+  * [da9254c] add README.source
+
+ -- Guido Guenther <agx@sigxcpu.org>  Fri, 08 Aug 2008 11:58:23 +0200
+
+calendarserver (1.2.dfsg-5) unstable; urgency=low
+
+  * [b52ad1f] remove dependency on python-plistlib, it's included in included
+    in python2.5 and in Debian's python2.4
+
+ -- Guido Guenther <agx@sigxcpu.org>  Fri, 08 Aug 2008 10:36:43 +0200
+
+calendarserver (1.2.dfsg-4) unstable; urgency=low
+
+  * [41eff3c] nss backend: use shortname for groups and users. The groupPrefix
+    makes sure these don't overlap. This way we don't have to use random uids
+    for the calendars on disk which makes administration a lot easier.
+  * [1d6701b] depend on python-openssl instead of the transitional
+    package python-pyopenssl
+  * [d90a173] refer to /usr/share/common-licenses/Apache-2.0 instead of
+    shipping the whole license
+  * [1937567] update upstream URL
+
+ -- Guido Guenther <agx@sigxcpu.org>  Sun, 22 Jun 2008 21:05:39 +0200
+
+calendarserver (1.2.dfsg-3) unstable; urgency=low
+
+  [ Guido Guenther ]
+  * upload to unstable - we no longer conflict on twisted
+  * [31d2b55] drop dependency on ctypes - it's already included in python2.5
+  * [652da62] Mention XFS (Closes: #483987) - thanks to Peter Mann
+  * [29edb85] add Homepage:
+  * [0c5bcee] redirect stderr to /dev/null on daemon restart This is a
+    temporary workaround until the twisted deprecation warnings got
+    fixed.
+
+  [ Noel Köthe ]
+  * [1c03474] xs- prefix from Vcs fields
+
+ -- Guido Guenther <agx@sigxcpu.org>  Thu, 19 Jun 2008 17:05:15 +0200
+
+calendarserver (1.2.dfsg-2) experimental; urgency=low
+
+  [ Guido Guenther ]
+  * fix epydoc errors
+  * use a python-twisted-calendarserver that doesn't ship the whole twisted
+    
+  [ Noel Köthe ]
+  * bind the caldavd only to localhost as described in README.Debian
+
+ -- Guido Guenther <agx@sigxcpu.org>  Mon, 05 May 2008 17:28:58 +0200
+
+calendarserver (1.2.dfsg-1) unstable; urgency=low
+
+  [ Guido Guenther ]
+  * New upstream 1.2
+  * add NSS directory backend
+  * bump python-twisted-calendarserver dependency to one that has the patches
+    for 1.2
+  * README.Debian: use non SSL port
+
+  [ Noel Köthe ]
+  * README.Debian:
+  	* s/sudoers.xml/sudoers.plist/
+  	* correcting path
+  * update TODO
+
+ -- Guido Guenther <agx@sigxcpu.org>  Sun, 27 Apr 2008 10:36:57 +0200
+
+calendarserver (1.2.dfsg~dev020221-5) unstable; urgency=low
+
+  * first upload to unstable
+  * tighten dependencies and drop suggests superflous suggests
+  * switch to Python 2.5
+  * README.Debian: add URI for group calendars
+
+ -- Guido Guenther <agx@sigxcpu.org>  Sun, 20 Apr 2008 13:59:04 +0200
+
+calendarserver (1.2.dfsg~dev020221-4) experimental; urgency=low
+
+  * update README.Debian on SPNEGO/Kerberos
+  * fix snakeoil certificate paths
+
+ -- Guido Guenther <agx@sigxcpu.org>  Sun, 16 Mar 2008 12:48:34 +0100
+
+calendarserver (1.2.dfsg~dev020221-3) experimental; urgency=low
+
+  * repackage upstream branch and remove RFCs too make the document dfsg clean
+  * add license of bin/xattr
+
+ -- Guido Guenther <agx@sigxcpu.org>  Wed, 27 Feb 2008 10:31:48 +0100
+
+calendarserver (1.2~dev020221-2) experimental; urgency=low
+
+  * disable the api-doc generation until it works with newer epydoc
+
+ -- Guido Guenther <agx@sigxcpu.org>  Tue, 26 Feb 2008 11:01:00 +0100
+
+calendarserver (1.2~dev020221-1) experimental; urgency=low
+
+  * first upload to experimental (Closes: #384644)
+  * switch to upstreams 1.2 development branch
+  * drop krb5 patch, applied upstream
+  * refreh paths.diff
+  * README.Debian: add calendar URI
+  * depend on renamed python-twisted-calendarserver package
+
+ -- Guido Guenther <agx@sigxcpu.org>  Thu, 21 Feb 2008 17:54:56 +0100
+
+calendarserver (0.0.svn1755-1) experimental; urgency=low
+
+  * UNRELEASED
+  * New Upstream SVN Snapshot
+  * update dependencies
+  * drop opendirectory-dummy.patch, not needed anymore, can be disabled via
+    the config file
+  * drop caldavd-kerberos.patch, not needed anymore. Kerberos can be enabled
+    via config file now
+  * update paths.diff to new layout and config options
+  * new fix-krb-service.diff: fix kerberos service names
+  * calendarserver.init: daemon switches users itself, new commandline options
+  * set process count to avoid pydirector for now
+
+ -- Guido Guenther <agx@sigxcpu.org>  Thu, 09 Aug 2007 10:24:46 +0200
+
+calendarserver (0.0.svn209-2) calendarserver; urgency=low
+
+  * create /var/run/caldavd (needed inc ase /var/run is on a tmpfs)
+  * drop dependencies on python-dateutil and python-zopeinterface since
+    these are indirect dependencies of python-vobject and
+    twisted-calendarserver respectively.
+  * build the api documentation 
+
+ -- Guido Guenther <agx@sigxcpu.org>  Mon,  2 Oct 2006 11:03:27 +0200
+
+calendarserver (0.0.svn209-1) calendarserver; urgency=low
+
+  * New Upstream Version
+  * depend on newer pykerberos 
+  * depend on newer twisted-calendarserver
+
+ -- Guido Guenther <agx@sigxcpu.org>  Wed, 27 Sep 2006 12:34:28 +0200
+
+calendarserver (0.0.svn197-1) calendarserver; urgency=low
+
+  * New Upstream Version
+  * depend on newer twisted
+  * twiddle path patch to apply again
+
+ -- Guido Guenther <agx@sigxcpu.org>  Tue, 26 Sep 2006 10:21:00 +0200
+
+calendarserver (0.0.svn188-1) unstable; urgency=low
+
+  * New upstream version 0.0.svn188
+  * bump dependencies on python-vobject
+  * depend on python-xml
+  * adjust patch path to look for twisted unter /usr/lib/caldavd
+    since we ship our own twisted version in this subdir now. This way
+    we don't have to conflict with the twisted shipped in Debian.
+  * depend on twisted-calendarserver (which was formerly
+    python-twisted-acl-branch)
+
+ -- Guido Guenther <agx@sigxcpu.org>  Mon, 25 Sep 2006 18:33:19 +0200
+
+calendarserver (0.0.svn142-3) unstable; urgency=low
+
+  * add a sample diff for kerberos authentication 
+
+ -- Guido Guenther <agx@sigxcpu.org>  Tue, 19 Sep 2006 10:06:53 +0200
+
+calendarserver (0.0.svn142-2) unstable; urgency=low
+
+  * depend on python-plistlib 
+
+ -- Guido Guenther <agx@sigxcpu.org>  Mon, 18 Sep 2006 19:54:24 +0200
+
+calendarserver (0.0.svn142-1) unstable; urgency=low
+
+  * new SVN version (only patches merged into twisted)
+  * depend on more recent twisted-acl-branch
+
+ -- Guido Guenther <agx@sigxcpu.org>  Mon, 18 Sep 2006 17:06:15 +0200
+
+calendarserver (0.0.svn135-2) unstable; urgency=low
+
+  * really drop upstream-patches/
+  * fix restart target in init script, use LSB logging
+  * add LSB header 
+
+ -- Guido Guenther <agx@sigxcpu.org>  Mon, 18 Sep 2006 16:00:45 +0200
+
+calendarserver (0.0.svn135-1) unstable; urgency=low
+
+  * New upstream svn version
+  * no need to rename patches to upstream-patches, upstream changed that to
+    lib-patches
+  * depend on newer twisted-acl-branch and newer pykerberos
+  * remove superflous heimdal-dev from build-depends
+  * dropped patches (applied upstream):
+     * bashism
+     * move-patch-dir
+     * linux-xattr
+  * use snake-oil certificates for SSL
+
+ -- Guido Guenther <agx@sigxcpu.org>  Fri, 15 Sep 2006 18:38:10 +0200
+
+calendarserver (0.0.svn62-1) unstable; urgency=low
+
+  * Initial release
+  * Add dummies for OpenDirectory interaction from:
+      http://svn.macosforge.org/projects/calendarserver/browser/PyOpenDirectory
+    until we have a proper port
+
+ -- Guido Guenther <agx@sigxcpu.org>  Wed,  6 Sep 2006 13:45:40 +0200
+
--- calendarserver-2.4.dfsg.orig/debian/calendarserver.default
+++ calendarserver-2.4.dfsg/debian/calendarserver.default
@@ -0,0 +1,8 @@
+# Defaults for calendarserver initscript (/etc/init.d/calendarserver)
+# This is a POSIX shell fragment
+
+# uncomment to start calendarserver on system startup
+#start_calendarserver=yes
+
+# options to pass to calendarserver on startup
+#DAEMON_OPTS=""
--- calendarserver-2.4.dfsg.orig/debian/calendarserver.examples
+++ calendarserver-2.4.dfsg/debian/calendarserver.examples
@@ -0,0 +1,5 @@
+conf/caldavd.plist
+conf/sudoers.plist
+conf/auth/accounts.xml
+conf/auth/accounts.htauth
+conf/auth/accounts.htdigest
--- calendarserver-2.4.dfsg.orig/debian/pycompat
+++ calendarserver-2.4.dfsg/debian/pycompat
@@ -0,0 +1 @@
+2
--- calendarserver-2.4.dfsg.orig/debian/README.Debian
+++ calendarserver-2.4.dfsg/debian/README.Debian
@@ -0,0 +1,123 @@
+calendar server for Debian
+==========================
+
+Basic Setup
+===========
+Since calendarserver uses extended attributes you must mount the filesystem
+that contains the calendars (/var/spool/caldavd by default) with extended
+attributes enabled. On ext2/ext3 filesystems use the user_xattr mount option,
+XFS has extended attributes enabled by default.
+
+You have to add a /etc/caldavd/accounts.xml to tell caldavd about your accounts
+and users. See /usr/share/doc/calendarserver/examples/accounts.xml for an
+example. Likewise you have to add a /etc/caldavd/sudoers.plist. Both files have
+to be present, otherwise the calendarserver will not work.
+
+By default calendarserver listens on localhost only so the URI to your caldav
+calendar will typically look like:
+
+ http://localhost:8008/calendars/users/<user>/calendar/
+
+where <user> is the username of a calendarserver user as specified in
+accounts.xml. And for groups defined in accounts.xml it's: 
+
+ http://localhost:8008/calendars/groups/<group>/calendar/
+
+
+Loadbalancing
+=============
+In order to enable laod balancing onto different processors/cores you need to
+install python-pydirecotor and set the ProcessCount in
+/etc/caldavd/caldavd.plist accordingly.
+
+
+Enabling SPNEGO/Kerberos
+========================
+
+To make SPNEGO/Kerberos authentication work you have to add service principals
+for HTTP/caldavd.example.com@EXAMPLE.COM and
+http/caldavd.example.com@EXAMPLE.COM to your servers keytab /etc/krb5.keytab
+(replace caldavd.example.com by the fqdn of your caldav server and EXAMPLE.COM
+by your Kerberos realm). 
+The uppercase http variant is used by most clients like iceowl and icedove with
+iceowl-extension while the lowercase version is used by iCal. The keytab must
+be readable for user caldavd which can be achieved by:
+
+chgrp caldavd /etc/krb5.keytab
+chmod 0640 /etc/krb5.keytab
+
+Now you have to specify the name of a ServicePrincipal in
+/etc/caldavd/caldavd.plist:
+
+    <!-- Kerberos/SPNEGO -->
+    <key>Kerberos</key>
+    <dict>
+      <key>Enabled</key>
+      <true/>
+      <key>ServicePrincipal</key>
+      <string>http/caldavd.example.com@EXAMPLE.COM</string>
+    </dict>
+
+Note: if you use iceowl/iceowl-extension the
+network.negotiate-auth.trusted-uris in iceowl/icedove must match on your
+calendarservers uri otherwise SPNEGO will not work. A good choice is
+"https://".
+
+
+Nameservice Switch Backend
+==========================
+If you don't want to manage accounts in a separate XML file you can use the
+names service switch backend. Details on how to set this up can be found at:
+
+http://honk.sigxcpu.org/con/Apple_Calendarser_with_Name_Service_Switch_directory_backend.html
+
+Note that in order to function properly "getent passwd" must list all users
+that should be able to access the calendarserver. This might not be the case if
+you hit the search limit of your LDAP server.
+
+Also note that the username and groupname (without the prefix) shouldn't be the same else
+calendarserver might get confused.
+
+PAM authentication is supported. The pam service name is "caldav". Basic Authentication should
+be enabled and Digest Authentication should be disabled for PAM authentication to work. It is
+suggested to use PAM authentication in conjunction with SSL (https) so that the password is not
+sent in plain text. For PAM authentication against local unix passwords, the user "caldavd"
+should be added to the "shadow" group.
+
+ -- Guido Guenther <agx@sigxcpu.org>  Thu, 30 Apr 2008 16:17:56 +0100
+
+
+LDAP Directory Backend
+======================
+Details of LDAP Directory backend can be found at:
+
+http://trac.calendarserver.org/ticket/260
+
+Possible authentication methods are "LDAP" (default) and "PAM". The pam service name is "caldav".
+For PAM/LDAP authentication, Basic Authentication should be enabled and Digest Authentication should
+be disabled (as shown below). It is suggested to use PAM/LDAP authentication in conjunction with
+SSL (https) so that the password is not sent in plain text. For PAM authentication against local
+unix passwords, the user "caldavd" should be added to the "shadow" group.
+
+    <!-- Clear text; best avoided -->
+    <key>Basic</key>
+    <dict>
+      <key>Enabled</key>
+      <true/>
+    </dict>
+
+    <!-- Digest challenge/response -->
+    <key>Digest</key>
+    <dict>
+      <key>Enabled</key>
+      <false/>
+      <key>Algorithm</key>
+      <string>md5</string>
+      <key>Qop</key>
+      <string></string>
+    </dict>
+
+For ldap anonymous binding, the dn and password entries should be present in the configuration file
+but their values should be empty.
+
+ -- Rahul Amaram <amaramrahul@users.sourceforge.net>  Tue, 24 Aug 2010 22:05:00 +0530
--- calendarserver-2.4.dfsg.orig/debian/NEWS
+++ calendarserver-2.4.dfsg/debian/NEWS
@@ -0,0 +1,7 @@
+calendarserver (2.4.dfsg-3) unstable; urgency=low
+
+  * Group calendaring has been disabled in calendarserver 2.x. For more information
+    on this, see http://trac.calendarserver.org/ticket/330. 
+
+ -- Rahul Amaram <amaramrahul@users.sourceforge.net>  Fri, 17 Dec 2010 00:00:00 +0530
+
--- calendarserver-2.4.dfsg.orig/debian/calendarserver.init.d
+++ calendarserver-2.4.dfsg/debian/calendarserver.init.d
@@ -0,0 +1,97 @@
+#! /bin/sh
+#
+# calendarserver startup script
+#
+### BEGIN INIT INFO
+# Provides:          caldavserver
+# Required-Start:    $remote_fs $network
+# Required-Stop:     $remote_fs $network
+# Default-Start:     2 3 4 5
+# Default-Stop:      0 1 6
+# Short-Description: CalDAV Calendarserver
+### END INIT INFO
+
+PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
+DAEMON=/usr/bin/caldavd
+NAME=caldavd
+DESC=calendarserver
+RUNDIR=/var/run/caldavd/
+SPOOLDIR=/var/spool/caldavd/
+
+test -x $DAEMON || exit 0
+
+# Include calendarserver defaults if available
+if [ -f /etc/default/calendarserver ] ; then
+	. /etc/default/calendarserver
+fi
+
+. /lib/lsb/init-functions
+
+set -e
+
+check_start_daemon() {
+  if [ ! "$start_calendarserver" = "yes" ]; then
+    log_warning_msg "Not starting calendarserver, disabled via /etc/default/calendarserver"
+    return 1
+  else
+    return 0
+  fi
+}
+
+case "$1" in
+  start)
+  	if check_start_daemon; then
+	    log_daemon_msg "Starting $DESC" "$NAME"
+	    mkdir -p $RUNDIR
+	    chown --reference=$SPOOLDIR $RUNDIR
+	    if start-stop-daemon --start --quiet --pidfile $RUNDIR$NAME.pid \
+		    --exec $DAEMON -- $DAEMON_OPTS 2>/dev/null; then
+	        log_end_msg 0
+	        RET=0
+	    else
+	        log_end_msg 1
+	        RET=1
+	    fi
+	fi
+	;;
+  stop)
+	log_daemon_msg "Stopping $DESC" "$NAME"
+	if start-stop-daemon --oknodo --stop --quiet --pidfile $RUNDIR$NAME.pid \
+		--exec /usr/bin/python; then
+	    log_end_msg 0
+	    RET=0
+	else
+	    log_end_msg 1
+	    RET=1
+	fi
+	;;
+  restart|force-reload)
+	#
+	#	If the "reload" option is implemented, move the "force-reload"
+	#	option to the "reload" entry above. If not, "force-reload" is
+	#	just the same as "restart".
+	#
+  	if check_start_daemon; then
+	    log_daemon_msg "Restarting $DESC" "$NAME"
+	    start-stop-daemon --stop --quiet --oknodo  --pidfile \
+		    $RUNDIR$NAME.pid --exec /usr/bin/python
+	    sleep 1
+	    if start-stop-daemon --start --quiet --pidfile \
+		    $RUNDIR$NAME.pid --exec $DAEMON -- $DAEMON_OPTS 2>/dev/null; then
+	        log_end_msg 0
+	        RET=0
+	    else
+	        log_end_msg 1
+	        RET=1
+	    fi
+	fi
+	;;
+  *)
+	N=/etc/init.d/$NAME
+	# echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2
+	echo "Usage: $N {start|stop|restart|force-reload}" >&2
+	exit 1
+	;;
+esac
+
+exit $RET
--- calendarserver-2.4.dfsg.orig/debian/compat
+++ calendarserver-2.4.dfsg/debian/compat
@@ -0,0 +1 @@
+5
--- calendarserver-2.4.dfsg.orig/debian/pyversions
+++ calendarserver-2.4.dfsg/debian/pyversions
@@ -0,0 +1 @@
+2.5-
--- calendarserver-2.4.dfsg.orig/debian/rules
+++ calendarserver-2.4.dfsg/debian/rules
@@ -0,0 +1,30 @@
+#!/usr/bin/make -f
+
+DEB_PYTHON_SYSTEM = pycentral
+  
+include /usr/share/cdbs/1/rules/debhelper.mk
+include /usr/share/cdbs/1/class/python-distutils.mk
+include /usr/share/cdbs/1/rules/patchsys-quilt.mk
+
+DEB_DESTDIR = $(CURDIR)/debian/calendarserver
+DEB_DH_INSTALLPAM_ARGS := --name=caldav
+
+calendarserver-doc-api-stamp:
+	#cd doc/Developer && pydoctor -c twistedcaldav.cfg --resolve-aliases --make-html
+	touch calendarserver-doc-api-stamp
+
+build/calendarserver-doc-api:: calendarserver-doc-api-stamp
+
+install/calendarserver::
+	rm -rf $(DEB_DESTDIR)
+	set -e; for buildver in $(cdbs_python_build_versions); do \
+		cd $(CURDIR) && cd $(DEB_SRCDIR) && python$$buildver setup.py install --root=$(DEB_DESTDIR) --install-purelib=/usr/lib/twisted-calendarserver/lib/python$$buildver/site-packages/ --install-platlib=/usr/lib/twisted-calendarserver/lib/python$$buildver/site-packages/ $(DEB_PYTHON_INSTALL_ARGS_ALL); \
+	done
+
+binary-fixup/calendarserver::
+	install -D -m 0755 -p -o root -g root $(CURDIR)/debian/upgrade-nss-data-directories.py $(DEB_DESTDIR)/usr/share/doc/calendarserver/scripts/upgrade-nss-data-directories.py
+
+clean::
+	-rm twistedcaldav/version.py
+	-rm -rf doc/Developer/apidocs calendarserver-doc-api-stamp
+
--- calendarserver-2.4.dfsg.orig/debian/calendarserver.TODO
+++ calendarserver-2.4.dfsg/debian/calendarserver.TODO
@@ -0,0 +1,2 @@
+
+
--- calendarserver-2.4.dfsg.orig/debian/calendarserver.caldav.pam
+++ calendarserver-2.4.dfsg/debian/calendarserver.caldav.pam
@@ -0,0 +1,6 @@
+#%PAM-1.0
+
+@include common-auth
+@include common-account
+@include common-session
+
--- calendarserver-2.4.dfsg.orig/debian/README.source
+++ calendarserver-2.4.dfsg/debian/README.source
@@ -0,0 +1,57 @@
+This package uses quilt to manage all modifications to the upstream
+source.  Changes are stored in the source package as diffs in
+debian/patches and applied during the build.
+
+To configure quilt to use debian/patches instead of patches, you want
+either to export QUILT_PATCHES=debian/patches in your environment
+or use this snippet in your ~/.quiltrc:
+
+    for where in ./ ../ ../../ ../../../ ../../../../ ../../../../../; do
+        if [ -e ${where}debian/rules -a -d ${where}debian/patches ]; then
+                export QUILT_PATCHES=debian/patches
+        fi
+    done
+
+To get the fully patched source after unpacking the source package, cd to
+the root level of the source package and run:
+
+    quilt push -a
+
+The last patch listed in debian/patches/series will become the current
+patch.
+
+To add a new set of changes, first run quilt push -a, and then run:
+
+    quilt new <patch>
+
+where <patch> is a descriptive name for the patch, used as the filename in
+debian/patches.  Then, for every file that will be modified by this patch,
+run:
+
+    quilt add <file>
+
+before editing those files.  You must tell quilt with quilt add what files
+will be part of the patch before making changes or quilt will not work
+properly.  After editing the files, run:
+
+    quilt refresh
+
+to save the results as a patch.
+
+Alternately, if you already have an external patch and you just want to
+add it to the build system, run quilt push -a and then:
+
+    quilt import -P <patch> /path/to/patch
+    quilt push -a
+
+(add -p 0 to quilt import if needed). <patch> as above is the filename to
+use in debian/patches.  The last quilt push -a will apply the patch to
+make sure it works properly.
+
+To remove an existing patch from the list of patches that will be applied,
+run:
+
+    quilt delete <patch>
+
+You may need to run quilt pop -a to unapply patches first before running
+this command.
--- calendarserver-2.4.dfsg.orig/debian/upgrade-nss-data-directories.py
+++ calendarserver-2.4.dfsg/debian/upgrade-nss-data-directories.py
@@ -0,0 +1,159 @@
+#!/usr/bin/python
+
+import os
+import shutil
+import pwd
+import grp
+import plistlib
+import copy
+import StringIO
+from uuid import UUID, uuid5
+
+
+def main():
+
+    # Init params
+    defaultConfigFile = "/etc/caldavd/caldavd.plist.upgrade.nss.tmp"
+    defaultConfig = {
+        "DirectoryService": {
+            "type": "twistedcaldav.directory.xmlfile.XMLDirectoryService",
+        },
+        "DocumentRoot": "/Library/CalendarServer/Documents",
+    }
+    serviceDefaultParams = {
+        "twistedcaldav.directory.nss.NssDirectoryService": {
+            "realmName": "Test Realm",
+            "groupPrefix": "caldavd-",
+            "firstValidUid": 1000,
+            "lastValidUid": 65533,
+            "firstValidGid": 1000,
+            "lastValidGid": 65533,
+        }
+    }
+    recordType_users = "users"
+    recordType_groups = "groups"
+    nssServiceBaseGUID = "8EFFFAF1-5221-4813-B971-58506B963573"
+
+    # Function to generate uuid from name
+    def uuidFromName(namespace, name):
+        """
+        Generate a version 5 (SHA-1) UUID from a namespace UUID and a name.
+        See http://www.ietf.org/rfc/rfc4122.txt, section 4.3.
+        @param namespace: a UUID denoting the namespace of the generated UUID.
+        @param name: a byte string to generate the UUID from.
+        """
+        # We don't want Unicode here; convert to UTF-8
+        if type(name) is unicode:
+            name = name.encode("utf-8")
+
+        return str(uuid5(UUID(namespace), name))
+
+    # Function to update config
+    def _update_config(configElement, defaultConfigElement):
+        for key, value in defaultConfigElement.iteritems():
+            if key not in configElement:
+                configElement[key] = copy.deepcopy(value)
+            elif isinstance(configElement[key], dict) and \
+                 isinstance(value, dict):
+                _update_config(configElement[key], value)
+
+
+    # Function to move individual user/group directory
+    def _move_directory(nssServiceGUID, documentRoot, recordType, shortName):
+        guid = uuidFromName(nssServiceGUID, "%s:%s" % (recordType, shortName))
+        olddir = os.path.join(documentRoot, "calendars", "__uids__", shortName)
+        newdir = os.path.join(documentRoot, "calendars", "__uids__", guid)
+        print "Moving directory for %s '%s' (GUID: %s) ..." % \
+              (recordType[:-1], shortName, guid)
+        if (not os.path.isdir(olddir)):
+            print "Old data directory '%s' does not exist. Nothing to move." % \
+                  (olddir)
+            return
+        if (os.path.isdir(newdir)):
+            print "New data directory '%s' already exists. Aborting move." % \
+                  (newdir)
+            return
+        shutil.move(olddir, newdir)
+        print "Data directory successfully moved from '%s' to '%s'." % \
+              (olddir, newdir)
+
+    # Begin
+    print ("Moving caldavd directories of NSS users and groups as the "
+           "directory names in calendarserver 2.x are based on UUID "
+           "rather than username/groupname as in calendarserver 1.x "
+           "(See Debian Bug#610124 for more info) ...\n")
+
+    # Check if config file exists.
+    if not os.path.isfile(defaultConfigFile):
+        print "Caldavd config file %s does not exist. Exiting." % \
+              (defaultConfigFile)
+        return
+
+    # Load configuration file
+    configPlist = plistlib.readPlist(defaultConfigFile)
+
+    # Update default configuration
+    s = StringIO.StringIO()
+    plistlib.writePlist(defaultConfig, s)
+    defaultConfigPlist = plistlib.readPlistFromString(s.getvalue())
+    _update_config(configPlist, defaultConfigPlist)
+
+    # If NSS is not the default directory service, exit
+    if configPlist.DirectoryService.type != \
+                "twistedcaldav.directory.nss.NssDirectoryService":
+        print "Directory service NssDirectoryService is not configured in " \
+              "%s. Exiting." % (defaultConfigFile)
+        return
+
+    # Update with service default params
+    s = StringIO.StringIO()
+    plistlib.writePlist(
+       {"params": serviceDefaultParams[
+                     "twistedcaldav.directory.nss.NssDirectoryService"]},
+       s
+    )
+    nssServiceDefaultParamsPlist = plistlib.readPlistFromString(s.getvalue())
+    _update_config(configPlist.DirectoryService, nssServiceDefaultParamsPlist)
+
+    # Generate serviceGUID
+    nssServiceGUID = uuidFromName(
+                        nssServiceBaseGUID,
+                        configPlist.DirectoryService.params.realmName
+                     )
+    print "NSS Directory Service GUID - %s\n" % (nssServiceGUID)
+
+    # Move users' data directories
+    print "Moving data directories of users ..."
+    users = pwd.getpwall()
+    for user in users:
+        if user[2] >= configPlist.DirectoryService.params.firstValidUid and \
+           user[2] <= configPlist.DirectoryService.params.lastValidUid:
+            _move_directory(
+                nssServiceGUID,
+                configPlist.DocumentRoot,
+                recordType_users,
+                user[0]
+            )
+            print
+
+    # Move groups' data directories
+    print "Moving data directories of groups ..."
+    groups = grp.getgrall()
+    for group in groups:
+        if group[2] >= configPlist.DirectoryService.params.firstValidGid and \
+           group[2] <= configPlist.DirectoryService.params.lastValidGid and \
+           group[0].startswith(configPlist.DirectoryService.params.groupPrefix):
+            _move_directory(
+                nssServiceGUID,
+                configPlist.DocumentRoot,
+                recordType_groups, 
+                group[0].replace(
+                    configPlist.DirectoryService.params.groupPrefix,'',1
+                )
+            )
+            print
+
+
+if __name__ == "__main__":
+    main()
+
--- calendarserver-2.4.dfsg.orig/debian/patches/secure-python-path.patch
+++ calendarserver-2.4.dfsg/debian/patches/secure-python-path.patch
@@ -0,0 +1,64 @@
+Removes setting PYTHONPATH in an insecure way, not needed on Debian.
+Removes "rewritting" rules from setup.py that did that.
+Index: b/setup.py
+===================================================================
+--- a/setup.py	2010-12-09 19:21:45.000000000 -0500
++++ b/setup.py	2010-12-09 19:22:25.000000000 -0500
+@@ -125,43 +125,3 @@
+     if root:
+         install_lib = install_lib[len(root):]
+ 
+-    for script in dist.scripts:
+-        scriptPath = os.path.join(install_scripts, os.path.basename(script))
+-
+-        print "rewriting %s" % (scriptPath,)
+-
+-        script = []
+-    
+-        fileType = None
+-
+-        for line in file(scriptPath, "r"):
+-            if not fileType:
+-                if line.startswith("#!"):
+-                    if "python" in line.lower():
+-                        fileType = "python"
+-                    elif "sh" in line.lower():
+-                        fileType = "sh"
+-
+-            line = line.rstrip("\n")
+-            if fileType == "sh":
+-                if line == "#PYTHONPATH":
+-                    script.append('PYTHONPATH="%s:$PYTHONPATH"' % (install_lib,))
+-                elif line == "#PATH":
+-                    script.append('PATH="%s:$PATH"' % (os.path.join(base, "bin"),))
+-                else:
+-                    script.append(line)
+-
+-            elif fileType == "python":
+-                if line == "#PYTHONPATH":
+-                    script.append('PYTHONPATH="%s"' % (install_lib,))
+-                elif line == "#PATH":
+-                    script.append('PATH="%s"' % (os.path.join(base, "bin"),))
+-                else:
+-                    script.append(line)
+-
+-            else:
+-                script.append(line)
+-
+-        newScript = open(scriptPath, "w")
+-        newScript.write("\n".join(script))
+-        newScript.close()
+Index: b/bin/caldavd
+===================================================================
+--- a/bin/caldavd	2010-12-09 19:21:51.000000000 -0500
++++ b/bin/caldavd	2010-12-09 19:22:41.000000000 -0500
+@@ -16,9 +16,6 @@
+ # limitations under the License.
+ ##
+ 
+-#PATH
+-#PYTHONPATH
+-
+ daemonize="";
+ username="";
+ groupname="";
--- calendarserver-2.4.dfsg.orig/debian/patches/paths.diff
+++ calendarserver-2.4.dfsg/debian/patches/paths.diff
@@ -0,0 +1,175 @@
+diff -Naur calendarserver-2.4.dfsg.orig/bin/caldavd calendarserver-2.4.dfsg/bin/caldavd
+--- calendarserver-2.4.dfsg.orig/bin/caldavd	2008-10-29 05:06:36.000000000 +0530
++++ calendarserver-2.4.dfsg/bin/caldavd	2010-08-24 21:59:30.000000000 +0530
+@@ -23,7 +23,7 @@
+ username="";
+ groupname="";
+ configfile="";
+-twistdpath="$(type -p twistd)";
++twistdpath="/usr/lib/twisted-calendarserver/bin/twistd";
+ plugin_name="caldav";
+ service_type="";
+ profile="";
+@@ -116,7 +116,7 @@
+ 
+ if [ $# != 0 ]; then usage "Unrecognized arguments:" "$@"; fi;
+ 
+-export PYTHONPATH
++export PYTHONPATH=`${python} -c 'import sys; print "/usr/lib/twisted-calendarserver/lib/python%s/site-packages" % (sys.version[:3])'`
+ 
+ echo exec "${python}" "${twistdpath}" "${twistd_reactor}" ${daemonize} ${username} ${groupname} "${plugin_name}" ${configfile} ${service_type} ${profile} "${child_reactor}";
+ 
+diff -Naur calendarserver-2.4.dfsg.orig/bin/calendarserver_export calendarserver-2.4.dfsg/bin/calendarserver_export
+--- calendarserver-2.4.dfsg.orig/bin/calendarserver_export	2009-05-08 02:42:08.000000000 +0530
++++ calendarserver-2.4.dfsg/bin/calendarserver_export	2010-08-24 21:59:30.000000000 +0530
+@@ -17,7 +17,7 @@
+ 
+ import sys
+ 
+-#PYTHONPATH
++PYTHONPATH = "/usr/lib/twisted-calendarserver/lib/python%s/site-packages" % (sys.version[:3])
+ 
+ if __name__ == "__main__":
+     if "PYTHONPATH" in globals():
+diff -Naur calendarserver-2.4.dfsg.orig/bin/calendarserver_manage_principals calendarserver-2.4.dfsg/bin/calendarserver_manage_principals
+--- calendarserver-2.4.dfsg.orig/bin/calendarserver_manage_principals	2009-05-08 02:59:14.000000000 +0530
++++ calendarserver-2.4.dfsg/bin/calendarserver_manage_principals	2010-08-24 21:59:30.000000000 +0530
+@@ -19,7 +19,7 @@
+ from __future__ import with_statement
+ import sys
+ 
+-#PYTHONPATH
++PYTHONPATH = "/usr/lib/twisted-calendarserver/lib/python%s/site-packages" % (sys.version[:3])
+ 
+ if __name__ == "__main__":
+     if "PYTHONPATH" in globals():
+diff -Naur calendarserver-2.4.dfsg.orig/bin/calendarserver_warmup calendarserver-2.4.dfsg/bin/calendarserver_warmup
+--- calendarserver-2.4.dfsg.orig/bin/calendarserver_warmup	2009-05-09 04:04:49.000000000 +0530
++++ calendarserver-2.4.dfsg/bin/calendarserver_warmup	2010-08-24 21:59:30.000000000 +0530
+@@ -17,7 +17,7 @@
+ 
+ import sys
+ 
+-#PYTHONPATH
++PYTHONPATH = "/usr/lib/twisted-calendarserver/lib/python%s/site-packages" % (sys.version[:3])
+ 
+ if __name__ == "__main__":
+     if "PYTHONPATH" in globals():
+diff -Naur calendarserver-2.4.dfsg.orig/conf/caldavd.plist calendarserver-2.4.dfsg/conf/caldavd.plist
+--- calendarserver-2.4.dfsg.orig/conf/caldavd.plist	2010-08-24 21:58:56.000000000 +0530
++++ calendarserver-2.4.dfsg/conf/caldavd.plist	2010-08-24 21:59:30.000000000 +0530
+@@ -36,13 +36,13 @@
+ 
+     <!-- HTTP port [0 = disable HTTP] -->
+     <key>HTTPPort</key>
+-    <integer>80</integer>
++    <integer>8008</integer>
+ 
+     <!-- SSL port [0 = disable HTTPS] -->
+     <!-- (Must also configure SSLCertificate and SSLPrivateKey below) -->
+     <!--
+     <key>SSLPort</key>
+-    <integer>443</integer>
++    <integer>8443</integer>
+     -->
+ 
+     <!-- Redirect non-SSL ports to an SSL port (if configured for SSL) -->
+@@ -78,11 +78,11 @@
+ 
+     <!-- Data root -->
+     <key>DataRoot</key>
+-    <string>/Library/CalendarServer/Data/</string>
++    <string>/var/lib/caldavd/</string>
+ 
+     <!-- Document root -->
+     <key>DocumentRoot</key>
+-    <string>/Library/CalendarServer/Documents/</string>
++    <string>/var/spool/caldavd/</string>
+ 
+     <!-- Child aliases -->
+     <key>Aliases</key>
+@@ -391,7 +391,7 @@
+ 
+     <!-- Global server stats --> 
+     <key>GlobalStatsSocket</key> 
+-    <string>/var/run/caldavd-stats.sock</string> 
++    <string>/var/run/caldavd/caldavd-stats.sock</string> 
+ 
+     <!-- Server statistics file -->
+     <key>ServerStatsFile</key>
+@@ -399,7 +399,7 @@
+ 
+     <!-- Server process ID file -->
+     <key>PIDFile</key>
+-    <string>/var/run/caldavd.pid</string>
++    <string>/var/run/caldavd/caldavd.pid</string>
+ 
+ 
+     <!--
+@@ -420,10 +420,10 @@
+       -->
+ 
+     <key>UserName</key>
+-    <string>daemon</string>
++    <string>caldavd</string>
+ 
+     <key>GroupName</key>
+-    <string>daemon</string>
++    <string>caldavd</string>
+ 
+     <key>ProcessType</key>
+     <string>Combined</string>
+@@ -431,7 +431,7 @@
+     <key>MultiProcess</key>
+     <dict>
+       <key>ProcessCount</key>
+-      <integer>0</integer> <!-- 0 = larger of: 4 or (2 * CPU count) -->
++      <integer>1</integer> <!-- 0 = larger of: 4 or (2 * CPU count) -->
+     </dict>
+ 
+ 
+@@ -588,6 +588,32 @@
+     <key>EnableWebAdmin</key>
+     <true/>
+ 
++    <!-- Twisted -->
++    <key>Twisted</key>
++    <dict>
++      <key>twistd</key>
++      <string>/usr/lib/twisted-calendarserver/bin/twistd</string>
++    </dict>
++
++    <!-- Python Director -->
++    <key>PythonDirector</key>
++    <dict>
++      <key>pydir</key>
++      <string>/usr/share/pydirector/pydir.py</string>
++      <key>ControlSocket</key>
++      <string>/var/run/caldavd/caldavd-pydir.sock</string>
++    </dict>
++
++    <!-- Control Socket -->
++    <key>ControlSocket</key>
++    <string>/var/run/caldavd/caldavd.sock</string>
++
++    <!-- Memcached -->
++    <key>Memcached</key>
++    <dict>
++      <key>ServerEnabled</key>
++      <false/>
++    </dict>
+ 
+   </dict>
+ </plist>
+diff -Naur calendarserver-2.4.dfsg.orig/setup.py calendarserver-2.4.dfsg/setup.py
+--- calendarserver-2.4.dfsg.orig/setup.py	2009-05-08 02:42:08.000000000 +0530
++++ calendarserver-2.4.dfsg/setup.py	2010-08-24 21:59:30.000000000 +0530
+@@ -110,7 +110,7 @@
+                          "bin/calendarserver_export",
+                          "bin/calendarserver_manage_principals"
+                        ],
+-    data_files       = [ ("caldavd", ["conf/caldavd.plist"]) ],
++    data_files       = [ ("/etc/caldavd", ["conf/caldavd.plist", "conf/sudoers.plist", "conf/auth/accounts.xml"]) ],
+     ext_modules      = extensions,
+     py_modules       = ["kqreactor", "memcacheclient"],
+ )
--- calendarserver-2.4.dfsg.orig/debian/patches/ldapdirectory.patch
+++ calendarserver-2.4.dfsg/debian/patches/ldapdirectory.patch
@@ -0,0 +1,634 @@
+Index: calendarserver-2.4.dfsg/conf/caldavd.plist
+===================================================================
+--- calendarserver-2.4.dfsg.orig/conf/caldavd.plist	2010-08-24 21:22:46.000000000 +0530
++++ calendarserver-2.4.dfsg/conf/caldavd.plist	2010-08-24 21:49:54.000000000 +0530
+@@ -191,6 +191,100 @@
+     </dict>
+      -->
+ 
++    <!--  OpenLDAP Directory Service -->
++    <!--
++    <key>DirectoryService</key>
++    <dict>
++      <key>type</key>
++      <string>twistedcaldav.directory.ldapdirectory.LdapDirectoryService</string>
++
++      <key>params</key>
++      <dict>
++        <key>cacheTimeout</key>
++        <integer>30</integer>
++        <key>realmName</key>
++        <string>Test Realm</string>
++        <key>uri</key>
++        <string>ldap://localhost:389/</string>
++        <key>tls</key>
++        <false/>
++        <key>tlsCACertFile</key>
++        <string></string>
++        <key>tlsCACertDir</key>
++        <string></string>
++        <key>tlsRequireCert</key>
++        <string>demand</string>
++        <key>credentials</key>
++        <dict>
++          <key>dn</key>
++          <string></string>
++          <key>password</key>
++          <string></string>
++        </dict>
++        <key>authMethod</key>
++        <string>PAM</string>
++        <key>rdnSchema</key>
++        <dict>
++          <key>base</key>
++          <string>dc=example,dc=com</string>
++          <key>guidAttr</key>
++          <string>entryUUID</string>
++          <key>users</key>
++          <dict>
++            <key>rdn</key>
++            <string>ou=People</string>
++            <key>attr</key>
++            <string>uid</string>
++            <key>emailSuffix</key>
++            <string></string>
++            <key>filter</key>
++            <string>(objectClass=inetOrgPerson)</string>
++          </dict>
++          <key>groups</key>
++          <dict>
++            <key>rdn</key>
++            <string>ou=Group</string>
++            <key>attr</key>
++            <string>cn</string>
++            <key>emailSuffix</key>
++            <string></string>
++            <key>filter</key>
++            <string></string>
++          </dict>
++          <key>locations</key>
++          <dict>
++            <key>rdn</key>
++            <string>ou=Locations</string>
++            <key>attr</key>
++            <string>cn</string>
++            <key>emailSuffix</key>
++            <string></string>
++            <key>filter</key>
++            <string></string>
++          </dict>
++          <key>resources</key>
++          <dict>
++            <key>rdn</key>
++            <string>ou=Resources</string>
++            <key>attr</key>
++            <string>cn</string>
++            <key>emailSuffix</key>
++            <string></string>
++            <key>filter</key>
++            <string></string>
++          </dict>
++        </dict>
++        <key>groupSchema</key>
++        <dict>
++          <key>membersAttr</key>
++          <string>member</string>
++          <key>memberIdAttr</key>
++          <string></string>
++        </dict>
++      </dict>
++    </dict>
++     -->
++
+     <!--
+         Special principals
+ 
+Index: calendarserver-2.4.dfsg/twistedcaldav/directory/ldapdirectory.py
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ calendarserver-2.4.dfsg/twistedcaldav/directory/ldapdirectory.py	2010-08-24 21:49:29.000000000 +0530
+@@ -0,0 +1,524 @@
++##
++# Copyright (c) 2008-2009 Aymeric Augustin. All rights reserved.
++#
++# Licensed under the Apache License, Version 2.0 (the "License");
++# you may not use this file except in compliance with the License.
++# You may obtain a copy of the License at
++#
++# http://www.apache.org/licenses/LICENSE-2.0
++#
++# Unless required by applicable law or agreed to in writing, software
++# distributed under the License is distributed on an "AS IS" BASIS,
++# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++# See the License for the specific language governing permissions and
++# limitations under the License.
++##
++
++"""
++LDAP directory service implementation.
++
++The following attributes from standard schemas are used:
++* Core (RFC 4519):
++    . cn | commonName
++    . givenName
++    . member (if not using NIS groups)
++    . ou
++    . sn | surname
++    . uid | userid (if using NIS groups)
++* COSINE (RFC 4524):
++    . mail
++* InetOrgPerson (RFC 2798):
++    . displayName (if cn is unavailable)
++* NIS (RFC):
++    . gecos (if cn is unavailable)
++    . memberUid (if using NIS groups)
++"""
++
++__all__ = [
++    "LdapDirectoryService",
++]
++
++import ldap
++import PAM
++
++from twisted.cred.credentials import UsernamePassword
++from twisted.web2.auth.digest import DigestedCredentials
++from twistedcaldav.directory.cachingdirectory import CachingDirectoryService,\
++    CachingDirectoryRecord
++
++
++class LdapDirectoryService(CachingDirectoryService):
++    """
++    LDAP based implementation of L{IDirectoryService}.
++    """
++    baseGUID = "5A871574-0C86-44EE-B11B-B9440C3DC4DD"
++
++    def __repr__(self):
++        return "<%s %r: %r>" % (self.__class__.__name__, self.realmName, self.uri)
++
++    def __init__(self, params, dosetup=True):
++        """
++        @param params: a dictionary containing the following keys:
++            cacheTimeout, realmName, uri, tls, tlsCACertFile, tlsCACertDir,
++            tlsRequireCert, crendentials, rdnSchema, groupSchema
++        @param dosetup: if C{True} then the directory records are initialized,
++                        if C{False} they are not.
++                        This should only be set to C{False} when doing unit tests.
++        """
++
++        defaults = {
++            "cacheTimeout": 30,
++            "realmName": "Test Realm",
++            "uri": "ldap://localhost/",
++            "tls": False,
++            "tlsCACertFile": None,
++            "tlsCACertDir": None,
++            "tlsRequireCert": None, # never, allow, try, demand/hard
++            "credentials": {
++                "dn": None,
++                "password": None,
++            },
++            "authMethod": "LDAP",
++            "rdnSchema": {
++                "base": "dc=example,dc=com",
++                "guidAttr": None,
++                "users": {
++                    "rdn": "ou=People",
++                    "attr": "uid",
++                    "emailSuffix": None,
++                    "filter": None,
++                },
++                "groups": {
++                    "rdn": "ou=Group",
++                    "attr": "cn",
++                    "emailSuffix": None,
++                    "filter": None,
++                },
++                "locations": {
++                    "rdn": "ou=Locations",
++                    "attr": "cn",
++                    "emailSuffix": None,
++                    "filter": None,
++                },
++                "resources": {
++                    "rdn": "ou=Resources",
++                    "attr": "cn",
++                    "emailSuffix": None,
++                    "filter": None,
++                },
++            },
++            "groupSchema": {
++                "membersAttr": "member",
++                "memberIdAttr": None,
++            },
++        }
++        ignored = None
++        params = self.getParams(params, defaults, ignored)
++
++        super(LdapDirectoryService, self).__init__(params['cacheTimeout'])
++
++        self.realmName = params['realmName']
++        self.uri = params['uri']
++        self.tls = params['tls']
++        self.tlsCACertFile = params['tlsCACertFile']
++        self.tlsCACertDir = params['tlsCACertDir']
++        self.tlsRequireCert = params['tlsRequireCert']
++        self.credentials = params['credentials']
++        self.authMethod = params['authMethod']
++        self.rdnSchema = params['rdnSchema']
++        self.groupSchema = params['groupSchema']
++
++        # Certain attributes (such as entryUUID) may be hidden and not
++        # returned by default when queried for all attributes. Therefore it is
++        # necessary to explicitly pass all the possible attributes list
++        # for ldap searches
++        attrSet = set(['mail', 'uid', 'userid', 'cn', 'commonName',
++                       'displayName', 'gecos', 'givenName', 'sn', 'surname'])
++        if self.rdnSchema['guidAttr']:
++            attrSet.add(self.rdnSchema['guidAttr'])
++        for recordType in self.recordTypes():
++            if self.rdnSchema[recordType]['attr']:
++                attrSet.add(self.rdnSchema[recordType]['attr'])
++        if self.groupSchema['membersAttr']:
++            attrSet.add(self.groupSchema['membersAttr'])
++        if self.groupSchema['memberIdAttr']:
++            attrSet.add(self.groupSchema['memberIdAttr'])
++        self.attrList = list(attrSet)
++
++        # Create LDAP connection
++        self.log_info("Calling ldap.ldapobject.ReconnectLDAPObject(%s)." % repr(self.uri), system="LdapDirectoryService")
++        self.ldap = ldap.ldapobject.ReconnectLDAPObject(self.uri)
++
++        # Open LDAP Connection
++        if self.tlsCACertFile:
++            ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, self.tlsCACertFile)
++        if self.tlsCACertDir:
++            ldap.set_option(ldap.OPT_X_TLS_CACERTDIR, self.tlsCACertDir)
++
++        if self.tlsRequireCert == "never":
++            self.ldap.set_option(ldap.OPT_X_TLS, ldap.OPT_X_TLS_NEVER)
++        elif self.tlsRequireCert == "allow":
++            self.ldap.set_option(ldap.OPT_X_TLS, ldap.OPT_X_TLS_ALLOW)
++        elif self.tlsRequireCert == "try":
++            self.ldap.set_option(ldap.OPT_X_TLS, ldap.OPT_X_TLS_TRY)
++        elif self.tlsRequireCert == "demand":
++            self.ldap.set_option(ldap.OPT_X_TLS, ldap.OPT_X_TLS_DEMAND)
++        elif self.tlsRequireCert == "hard":
++            self.ldap.set_option(ldap.OPT_X_TLS, ldap.OPT_X_TLS_HARD)
++
++        if self.tls:
++            self.ldap.start_tls_s()
++
++        if self.credentials.get('dn', ''):
++            try:
++                self.log_info("Calling LDAPObject.simple_bind_s(%s, [password])." % repr(self.credentials.get('dn')), system="LdapDirectoryService")
++                self.ldap.simple_bind_s(self.credentials.get('dn'), self.credentials.get('password'))
++            except ldap.INVALID_CREDENTIALS:
++                self.log_error("Unable to bind to LDAP server %s: check credentials." % self.uri, system="LdapDirectoryService")
++                raise
++
++    def __del__(self):
++        try: self.ldap.unbind_s()
++        except: pass
++
++    def recordTypes(self):
++        return (
++            self.recordType_users,
++            self.recordType_groups,
++            self.recordType_locations,
++            self.recordType_resources,
++        )
++
++    # Get the first value for one or several attributes
++    # Useful when attributes have aliases (e.g. sn vs. surname)
++    def _getUniqueLdapAttribute(self, attrs, *keys):
++        for key in keys:
++            values = attrs.get(key)
++            if values is not None:
++                return values[0]
++        return None
++
++    # Get all values for one or several attributes
++    def _getMultipleLdapAttributes(self, attrs, *keys):
++        results = []
++        for key in keys:
++            values = attrs.get(key)
++            if values is not None:
++                results += values
++        return set(results)
++
++    # Convert the attrs returned by a LDAP search into a LdapDirectoryRecord object
++    # Mappings are hardcoded below but the most standard LDAP schemas were used
++    # to define them
++    def _ldapResultToRecord(self, dn, attrs, recordType):
++        guid = None
++        shortNames  = ()
++        authIDs = set()
++        fullName = None
++        firstName = None
++        lastName = None
++        emailAddresses = set()
++        calendarUserAddresses = set()
++        enabledForCalendaring = None
++        uid = None
++
++        # First check for and add guid
++        guidAttr = self.rdnSchema['guidAttr']
++        if guidAttr:
++            guid = self._getUniqueLdapAttribute(attrs, guidAttr)
++
++        # Find or build email
++        emailAddresses = set(map(lambda v: 'mailto:' + v, self._getMultipleLdapAttributes(attrs, 'mail')))
++        emailSuffix = self.rdnSchema[recordType]['emailSuffix']
++        if len(emailAddresses) == 0 and emailSuffix is not None:
++            emailPrefix = self._getUniqueLdapAttribute(attrs, self.rdnSchema[recordType]['attr'])
++            emailAddresses.add('mailto:' + emailPrefix + emailSuffix)
++
++        # LDAP attribute -> principal matchings
++        if recordType == self.recordType_users:
++            shortNames = (self._getUniqueLdapAttribute(attrs, 'uid', 'userid'),)
++            fullName = self._getUniqueLdapAttribute(attrs, 'cn', 'commonName', 'displayName', 'gecos')
++            firstName = self._getUniqueLdapAttribute(attrs, 'givenName')
++            lastName = self._getUniqueLdapAttribute(attrs, 'sn', 'surname')
++            calendarUserAddresses = emailAddresses
++            enabledForCalendaring = True
++        elif recordType == self.recordType_groups:
++            shortNames = (self._getUniqueLdapAttribute(attrs, 'cn'),)
++            fullName = self._getUniqueLdapAttribute(attrs, 'cn')
++            enabledForCalendaring = False
++        elif recordType in (self.recordType_resources, self.recordType_locations):
++            shortNames = (self._getUniqueLdapAttribute(attrs, 'cn'),)
++            fullName = self._getUniqueLdapAttribute(attrs, 'cn')
++            calendarUserAddresses = emailAddresses
++            enabledForCalendaring = True
++
++        return LdapDirectoryRecord(
++            service     = self,
++            recordType  = recordType,
++            guid        = guid,
++            shortNames  = shortNames,
++            authIDs     = authIDs,
++            fullName    = fullName,
++            firstName   = firstName,
++            lastName    = lastName,
++            emailAddresses          = emailAddresses,
++            calendarUserAddresses   = calendarUserAddresses,
++            enabledForCalendaring   = enabledForCalendaring,
++            uid        = uid,
++            dn         = dn,
++            attrs      = attrs,
++        )
++
++
++    def queryDirectory(self, recordTypes, indexType, indexKey):
++        self.log_debug("Querying directory for recordTypes %s, indexType %s and indexKey %s"
++                      % (recordTypes, indexType, indexKey),
++                      system="LdapDirectoryService")
++        for recordType in recordTypes:
++            # Build base for this record Type
++            base = ldap.dn.str2dn(self.rdnSchema[recordType]['rdn']) + ldap.dn.str2dn(self.rdnSchema['base'])
++
++            # Build filter
++            filter = "(!(objectClass=organizationalUnit))"
++            if self.rdnSchema[recordType]['filter']:
++                filter = "(&%s%s)" % (filter, self.rdnSchema[recordType]['filter'])
++            if indexType == self.INDEX_TYPE_GUID:
++                # Quey on guid only works if guid attribute has been defined.
++                # Support for query on guid even if is auto-generated should
++                # be added.
++                guidAttr = self.rdnSchema['guidAttr']
++                if not guidAttr: return
++                filter = "(&%s(%s=%s))" % (filter, guidAttr, indexKey)
++            elif indexType == self.INDEX_TYPE_SHORTNAME:
++                if recordType == self.recordType_users:
++                    filter = "(&%s(|(uid=%s)(userid=%s)))" % (filter, indexKey, indexKey)
++                elif recordType in (self.recordType_groups, self.recordType_resources, self.recordType_locations):
++                    filter = "(&%s(cn=%s))" % (filter, indexKey)
++            elif indexType == self.INDEX_TYPE_CUA:
++                # indexKey is of the form "mailto:test@example.net"
++                email = indexKey[7:] # strip "mailto:"
++                emailSuffix = self.rdnSchema[recordType]['emailSuffix']
++                if emailSuffix is not None and email.partition("@")[2] == emailSuffix:
++                    filter = "(&%s(|(&(!(mail=*))(%s=%s))(mail=%s)))" % \
++                             (filter, self.rdnSchema[recordType]['attr'],
++                              email.partition("@")[0], email)
++                else:
++                    filter = "(&%s(mail=%s))" % (filter, email)
++            elif indexType == self.INDEX_TYPE_AUTHID:
++                return
++
++            # Query the LDAP server
++            self.log_info("Retrieving ldap record with base %s and filter %s." %
++                          (ldap.dn.dn2str(base), filter),
++                          system="LdapDirectoryService")
++            result = self.ldap.search_s(ldap.dn.dn2str(base), ldap.SCOPE_SUBTREE, filter, self.attrList)
++
++            if result:
++                dn, attrs = result.pop()
++                self.recordCacheForType(recordType).addRecord(
++                        self._ldapResultToRecord(dn, attrs, recordType),
++                        indexType, indexKey
++                )
++
++
++
++class LdapDirectoryRecord(CachingDirectoryRecord):
++    """
++    LDAP implementation of L{IDirectoryRecord}.
++    """
++    def __init__(
++        self, service, recordType,
++        guid, shortNames, authIDs, fullName,
++        firstName, lastName, emailAddresses,
++        calendarUserAddresses, enabledForCalendaring, uid,
++        dn, attrs
++    ):
++        super(LdapDirectoryRecord, self).__init__(
++            service               = service,
++            recordType            = recordType,
++            guid                  = guid,
++            shortNames            = shortNames,
++            authIDs               = authIDs,
++            fullName              = fullName,
++            firstName             = firstName,
++            lastName              = lastName,
++            emailAddresses        = emailAddresses,
++            calendarUserAddresses = calendarUserAddresses,
++            enabledForCalendaring = enabledForCalendaring,
++            uid                   = uid,
++        )
++
++        # Save attributes of dn and attrs in case you might need them later
++        self.dn = dn
++        self.attrs = attrs
++
++        # Identifiers of the members of this record if it is a group
++        membersAttr = self.service.groupSchema['membersAttr']
++        self._memberIds = self.service._getMultipleLdapAttributes(attrs, membersAttr)
++
++        # Identifier of this record as a group member
++        memberIdAttr = self.service.groupSchema['memberIdAttr']
++        if memberIdAttr:
++            self._memberId = self.service._getUniqueLdapAttribute(attrs, memberIdAttr)
++        else:
++            self._memberId = self.dn
++
++
++    # Singleton with lazy loading
++    def _ldap(self):
++        try:
++            return self.ldap
++        except AttributeError:
++            # Use a different LDAP connection for authentication
++            # in order not to re-bind the server connection at each verification
++            self.log_info("Calling ldap.ldapobject.ReconnectLDAPObject(%s) in %s." % (repr(self.service.uri), repr(self)),
++                          system="LdapDirectoryService")
++            self.ldap = ldap.ldapobject.ReconnectLDAPObject(self.service.uri)
++
++            if self.service.tlsCACertFile:
++                ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, self.service.tlsCACertFile)
++            if self.service.tlsCACertDir:
++                ldap.set_option(ldap.OPT_X_TLS_CACERTDIR, self.service.tlsCACertDir)
++
++            if self.service.tlsRequireCert == "never":
++                self.ldap.set_option(ldap.OPT_X_TLS, ldap.OPT_X_TLS_NEVER)
++            elif self.service.tlsRequireCert == "allow":
++                self.ldap.set_option(ldap.OPT_X_TLS, ldap.OPT_X_TLS_ALLOW)
++            elif self.service.tlsRequireCert == "try":
++                self.ldap.set_option(ldap.OPT_X_TLS, ldap.OPT_X_TLS_TRY)
++            elif self.service.tlsRequireCert == "demand":
++                self.ldap.set_option(ldap.OPT_X_TLS, ldap.OPT_X_TLS_DEMAND)
++            elif self.service.tlsRequireCert == "hard":
++                self.ldap.set_option(ldap.OPT_X_TLS, ldap.OPT_X_TLS_HARD)
++
++            if self.service.tls:
++                self.ldap.start_tls_s()
++
++            return self.ldap
++
++    def _members(self):
++        # Only groups have members
++        memberIdAttr = self.service.groupSchema['memberIdAttr']
++        results = []
++        for memberId in self._memberIds:
++            if memberIdAttr:
++                base = self.service._base
++                filter = '(%s=%s)' % (self.service.groupSchema['memberIdAttr'], memberId)
++                self.log_info("Retrieving subtree of %s with filter %s." % (ldap.dn.dn2str(base), filter),
++                             system="LdapDirectoryService")
++                result = self.service.ldap.search_s(ldap.dn.dn2str(base), ldap.SCOPE_SUBTREE, filter, self.service.attrList)
++            else:
++                self.log_info("Retrieving %s." % memberId, system="LdapDirectoryService")
++                result = self.service.ldap.search_s(memberId, ldap.SCOPE_BASE, attrlist=self.service.attrList)
++
++            assert len(result) == 1
++            dn, attrs = result.pop()
++
++            # Guess the recordType for the member (using scope bleeding)
++            for recordType in self.service.recordTypes():
++                attr = self.service.rdnSchema[recordType]['attr']
++                value = self.service._getUniqueLdapAttribute(attrs, attr)
++                calcDn = [[(attr, value, 1)]] + ldap.dn.str2dn(self.service.rdnSchema[recordType]['rdn']) \
++                                              + ldap.dn.str2dn(self.service.rdnSchema['base'])
++                if dn.lower() == ldap.dn.dn2str(calcDn).lower():
++                    break
++
++            if recordType == self.service.recordType_users:
++                shortName = self.service._getUniqueLdapAttribute(attrs, 'uid', 'userid')
++            elif recordType in (self.service.recordType_groups, self.service.recordType_resources,
++                                self.service.recordType_locations):
++                shortName = self.service._getUniqueLdapAttribute(attrs, 'cn')
++            results.append(self.service.recordWithShortName(recordType, shortName))
++
++        return results
++
++    def _groups(self):
++        recordType = self.service.recordType_groups
++        base =  ldap.dn.str2dn(self.service.rdnSchema[recordType]['rdn']) + \
++                ldap.dn.str2dn(self.service.rdnSchema['base'])
++        filter = '(%s=%s)' % (self.service.groupSchema['membersAttr'], self._memberId)
++        self.log_info("Retrieving subtree of %s with filter %s." % (ldap.dn.dn2str(base), filter),
++                     system="LdapDirectoryService")
++        results = self.service.ldap.search_s(ldap.dn.dn2str(base), ldap.SCOPE_SUBTREE, filter, self.service.attrList)
++
++        groups = []
++        for dn, attrs in results:
++            if recordType == self.service.recordType_users:
++                shortName = self.service._getUniqueLdapAttribute(attrs, 'uid', 'userid')
++            elif recordType in (self.service.recordType_groups, self.service.recordType_resources,
++                                self.service.recordType_locations):
++                shortName = self.service._getUniqueLdapAttribute(attrs, 'cn')
++            groups.append(self.service.recordWithShortName(recordType, shortName))
++
++        return groups
++
++    # There is no need to implement a timeout here, the LdapDirectoryRecord objects
++    # themselves are destroyed and re-created when the records list is refreshed
++    # in LdapDirectoryService.
++
++    def members(self):
++        try:
++            return self._members_storage
++        except AttributeError:
++            self._members_storage = self._members()
++            return self._members_storage
++
++    def groups(self):
++        try:
++            return self._groups_storage
++        except AttributeError:
++            self._groups_storage = self._groups()
++            return self._groups_storage
++
++
++    # Credentials are checked against PAM
++    # Thus, the password is needed in clear-text and digest authentication
++    # can not be supported.
++    def verifyCredentials(self, credentials):
++        if isinstance(credentials, UsernamePassword):
++            # Check that the username supplied matches one of the shortNames
++            # (The DCS might already enforce this constraint, not sure)
++            if credentials.username not in self.shortNames:
++                return False
++
++            # Check cached password
++            try:
++                if credentials.password == self.password:
++                    return True
++            except AttributeError:
++                pass
++
++            if not self.service.authMethod or self.service.authMethod.upper() == "PAM":
++                # Authenticate against PAM
++                def pam_conv(auth, query_list, userData):
++                    return [(credentials.password, 0)]
++
++                auth = PAM.pam()
++                auth.start("caldav")
++                auth.set_item(PAM.PAM_USER, credentials.username)
++                auth.set_item(PAM.PAM_CONV, pam_conv)
++                try:
++                    auth.authenticate()
++                except PAM.error, resp:
++                    return False
++                else:
++                    # Cache the password to avoid further LDAP queries
++                    self.password = credentials.password
++                    return True
++            elif self.service.authMethod.upper() == "LDAP":
++                # Authenticate against LDAP
++                try:
++                    self.log_info("Calling LDAPObject.simple_bind_s(%s, [password])." % repr(self.dn), system="LdapDirectoryService")
++                    self.log_info(self._ldap().bind_s(self.dn, credentials.password))
++                    # Cache the password to avoid further LDAP queries
++                    self.password = credentials.password
++                    return True
++                except ldap.INVALID_CREDENTIALS:
++                    return False
++            else:
++                err_msg = "Unknown Authentication Method '%s'" % (self.service.authMethod.upper())
++                self.log_error(err_msg)
++                raise err_msg
++
++        return super(LdapDirectoryRecord, self).verifyCredentials(credentials)
++
--- calendarserver-2.4.dfsg.orig/debian/patches/linux-xattr-fix.patch
+++ calendarserver-2.4.dfsg/debian/patches/linux-xattr-fix.patch
@@ -0,0 +1,182 @@
+diff -Naur calendarserver-2.4.dfsg.orig/calendarserver/tools/doublequotefix.py calendarserver-2.4.dfsg/calendarserver/tools/doublequotefix.py
+--- calendarserver-2.4.dfsg.orig/calendarserver/tools/doublequotefix.py	2009-01-06 00:27:18.000000000 +0530
++++ calendarserver-2.4.dfsg/calendarserver/tools/doublequotefix.py	2010-07-28 16:58:55.000000000 +0530
+@@ -56,14 +56,14 @@
+ def updateEtag(path, caldata):
+ 
+     x = xattr.xattr(path)
+-    x["WebDAV:{http:%2F%2Ftwistedmatrix.com%2Fxml_namespace%2Fdav%2F}getcontentmd5"] = """<?xml version='1.0' encoding='UTF-8'?>
++    x["user.{http:%2F%2Ftwistedmatrix.com%2Fxml_namespace%2Fdav%2F}getcontentmd5"] = """<?xml version='1.0' encoding='UTF-8'?>
+ <getcontentmd5 xmlns='http://twistedmatrix.com/xml_namespace/dav/'>%s</getcontentmd5>
+ """ % (hashlib.md5(caldata).hexdigest(),)
+ 
+ def updateCtag(path):
+ 
+     x = xattr.xattr(path)
+-    x["WebDAV:{http:%2F%2Fcalendarserver.org%2Fns%2F}getctag"] = """<?xml version='1.0' encoding='UTF-8'?>
++    x["user.{http:%2F%2Fcalendarserver.org%2Fns%2F}getctag"] = """<?xml version='1.0' encoding='UTF-8'?>
+ <getctag xmlns='http://calendarserver.org/ns/'>%s</getctag>
+ """ % (str(datetime.datetime.now()),)
+ 
+diff -Naur calendarserver-2.4.dfsg.orig/calendarserver/tools/fixcalendardata.py calendarserver-2.4.dfsg/calendarserver/tools/fixcalendardata.py
+--- calendarserver-2.4.dfsg.orig/calendarserver/tools/fixcalendardata.py	2009-05-06 01:12:00.000000000 +0530
++++ calendarserver-2.4.dfsg/calendarserver/tools/fixcalendardata.py	2010-07-28 16:58:33.000000000 +0530
+@@ -61,14 +61,14 @@
+ def updateEtag(path, caldata):
+ 
+     x = xattr.xattr(path)
+-    x["WebDAV:{http:%2F%2Ftwistedmatrix.com%2Fxml_namespace%2Fdav%2F}getcontentmd5"] = """<?xml version='1.0' encoding='UTF-8'?>
++    x["user.{http:%2F%2Ftwistedmatrix.com%2Fxml_namespace%2Fdav%2F}getcontentmd5"] = """<?xml version='1.0' encoding='UTF-8'?>
+ <getcontentmd5 xmlns='http://twistedmatrix.com/xml_namespace/dav/'>%s</getcontentmd5>
+ """ % (hashlib.md5(caldata).hexdigest(),)
+ 
+ def updateCtag(path):
+ 
+     x = xattr.xattr(path)
+-    x["WebDAV:{http:%2F%2Fcalendarserver.org%2Fns%2F}getctag"] = """<?xml version='1.0' encoding='UTF-8'?>
++    x["user.{http:%2F%2Fcalendarserver.org%2Fns%2F}getctag"] = """<?xml version='1.0' encoding='UTF-8'?>
+ <getctag xmlns='http://calendarserver.org/ns/'>%s</getctag>
+ """ % (str(datetime.datetime.now()),)
+ 
+@@ -101,7 +101,7 @@
+     for item in os.listdir(calendarHome):
+         calendarPath = os.path.join(calendarHome, item)
+         x = xattr.xattr(calendarPath)
+-        if x.has_key("WebDAV:{http:%2F%2Fcalendarserver.org%2Fns%2F}getctag"):
++        if x.has_key("user.{http:%2F%2Fcalendarserver.org%2Fns%2F}getctag"):
+             scanCalendar(basePath, calendarPath, scanFile, doFix)
+ 
+ def scanCalendar(basePath, calendarPath, scanFile, doFix):
+diff -Naur calendarserver-2.4.dfsg.orig/contrib/tools/fix_calendar calendarserver-2.4.dfsg/contrib/tools/fix_calendar
+--- calendarserver-2.4.dfsg.orig/contrib/tools/fix_calendar	2008-06-24 02:02:56.000000000 +0530
++++ calendarserver-2.4.dfsg/contrib/tools/fix_calendar	2010-07-28 16:59:48.000000000 +0530
+@@ -44,14 +44,14 @@
+     
+     # First fix the resourcetype & getctag on the calendar
+     x = xattr.xattr(path)
+-    x["WebDAV:{DAV:}resourcetype"] = """<?xml version='1.0' encoding='UTF-8'?>
++    x["user.{DAV:}resourcetype"] = """<?xml version='1.0' encoding='UTF-8'?>
+ <resourcetype xmlns='DAV:'>
+   <collection/>
+   <calendar xmlns='urn:ietf:params:xml:ns:caldav'/>
+ </resourcetype>
+ """
+ 
+-    x["WebDAV:{http:%2F%2Fcalendarserver.org%2Fns%2F}getctag"] = """<?xml version='1.0' encoding='UTF-8'?>
++    x["user.{http:%2F%2Fcalendarserver.org%2Fns%2F}getctag"] = """<?xml version='1.0' encoding='UTF-8'?>
+ <getctag xmlns='http://calendarserver.org/ns/'>Dummy Value</getctag>
+ """
+ 
+@@ -63,13 +63,13 @@
+         
+         # getcontenttype
+         x = xattr.xattr(fullpath)
+-        x["WebDAV:{DAV:}getcontenttype"] = """<?xml version='1.0' encoding='UTF-8'?>
++        x["user.{DAV:}getcontenttype"] = """<?xml version='1.0' encoding='UTF-8'?>
+ <getcontenttype xmlns='DAV:'>text/calendar</getcontenttype>
+ """
+ 
+         # md5
+         data = open(fullpath).read()
+-        x["WebDAV:{http:%2F%2Ftwistedmatrix.com%2Fxml_namespace%2Fdav%2F}getcontentmd5"] = """<?xml version='1.0' encoding='UTF-8'?>
++        x["user.{http:%2F%2Ftwistedmatrix.com%2Fxml_namespace%2Fdav%2F}getcontentmd5"] = """<?xml version='1.0' encoding='UTF-8'?>
+ <getcontentmd5 xmlns='http://twistedmatrix.com/xml_namespace/dav/'>%s</getcontentmd5>
+ """ % (hashlib.md5(data).hexdigest(),)
+ 
+@@ -103,4 +103,4 @@
+ 
+     except Exception, e:
+         sys.exit(str(e))
+-    
+\ No newline at end of file
++    
+diff -Naur calendarserver-2.4.dfsg.orig/twistedcaldav/admin/util.py calendarserver-2.4.dfsg/twistedcaldav/admin/util.py
+--- calendarserver-2.4.dfsg.orig/twistedcaldav/admin/util.py	2009-04-22 09:10:46.000000000 +0530
++++ calendarserver-2.4.dfsg/twistedcaldav/admin/util.py	2010-07-28 17:01:30.000000000 +0530
+@@ -92,7 +92,7 @@
+ 
+ 
+ def getPrincipalType(fp):
+-    rtp = "WebDAV:" + RecordTypeProperty.sname().replace("/", "%2F")
++    rtp = "user." + RecordTypeProperty.sname().replace("/", "%2F")
+     x = xattr.xattr(fp.path)
+     if not x.has_key(rtp):
+         return None
+@@ -103,7 +103,7 @@
+     return rtp[0].firstChild().value
+     
+ def getResourceType(fp):
+-    rt = 'WebDAV:{DAV:}resourcetype'
++    rt = 'user.{DAV:}resourcetype'
+     x = xattr.xattr(fp.path)
+     if not x.has_key(rt):
+         return None
+@@ -173,8 +173,8 @@
+ 
+ from twisted.web2.dav.resource import TwistedQuotaRootProperty, TwistedQuotaUsedProperty
+ 
+-quotaRoot = "WebDAV:" + TwistedQuotaRootProperty.sname().replace("/", "%2F")
+-quotaUsed = "WebDAV:" + TwistedQuotaUsedProperty.sname().replace("/", "%2F")
++quotaRoot = "user." + TwistedQuotaRootProperty.sname().replace("/", "%2F")
++quotaUsed = "user." + TwistedQuotaUsedProperty.sname().replace("/", "%2F")
+ 
+ def getQuotaRoot(fp):
+     x = xattr.xattr(fp.path)
+diff -Naur calendarserver-2.4.dfsg.orig/twistedcaldav/test/data/makelargefbset.py calendarserver-2.4.dfsg/twistedcaldav/test/data/makelargefbset.py
+--- calendarserver-2.4.dfsg.orig/twistedcaldav/test/data/makelargefbset.py	2007-12-12 06:28:32.000000000 +0530
++++ calendarserver-2.4.dfsg/twistedcaldav/test/data/makelargefbset.py	2010-07-28 17:00:43.000000000 +0530
+@@ -45,7 +45,7 @@
+     
+         inboxname = os.path.join(path, "inbox")
+         attrs = xattr.xattr(inboxname)
+-        attrs["WebDAV:{urn:ietf:params:xml:ns:caldav}calendar-free-busy-set"] = """<?xml version='1.0' encoding='UTF-8'?>
++        attrs["user.{urn:ietf:params:xml:ns:caldav}calendar-free-busy-set"] = """<?xml version='1.0' encoding='UTF-8'?>
+     <calendar-free-busy-set xmlns='urn:ietf:params:xml:ns:caldav'>
+       <href xmlns='DAV:'>/calendars/users/user%02d/calendar/</href>
+       <href xmlns='DAV:'>/calendars/users/user%02d/calendar.1000/</href>
+diff -Naur calendarserver-2.4.dfsg.orig/twistedcaldav/test/test_upgrade.py calendarserver-2.4.dfsg/twistedcaldav/test/test_upgrade.py
+--- calendarserver-2.4.dfsg.orig/twistedcaldav/test/test_upgrade.py	2009-11-19 01:35:55.000000000 +0530
++++ calendarserver-2.4.dfsg/twistedcaldav/test/test_upgrade.py	2010-07-28 17:00:20.000000000 +0530
+@@ -29,9 +29,9 @@
+ import hashlib
+ import os, zlib, cPickle
+ 
+-freeBusyAttr = "WebDAV:{urn:ietf:params:xml:ns:caldav}calendar-free-busy-set"
+-cTagAttr = "WebDAV:{http:%2F%2Fcalendarserver.org%2Fns%2F}getctag"
+-md5Attr = "WebDAV:{http:%2F%2Ftwistedmatrix.com%2Fxml_namespace%2Fdav%2F}getcontentmd5"
++freeBusyAttr = "user.{urn:ietf:params:xml:ns:caldav}calendar-free-busy-set"
++cTagAttr = "user.{http:%2F%2Fcalendarserver.org%2Fns%2F}getctag"
++md5Attr = "user.{http:%2F%2Ftwistedmatrix.com%2Fxml_namespace%2Fdav%2F}getcontentmd5"
+ 
+ 
+ class ProxyDBUpgradeTests(TestCase):
+diff -Naur calendarserver-2.4.dfsg.orig/twistedcaldav/upgrade.py calendarserver-2.4.dfsg/twistedcaldav/upgrade.py
+--- calendarserver-2.4.dfsg.orig/twistedcaldav/upgrade.py	2009-11-19 01:21:02.000000000 +0530
++++ calendarserver-2.4.dfsg/twistedcaldav/upgrade.py	2010-07-28 17:01:06.000000000 +0530
+@@ -156,7 +156,7 @@
+ 
+                 md5value = "<?xml version='1.0' encoding='UTF-8'?>\r\n<getcontentmd5 xmlns='http://twistedmatrix.com/xml_namespace/dav/'>%s</getcontentmd5>\r\n" % (hashlib.md5(data).hexdigest(),)
+                 md5value = zlib.compress(md5value)
+-                xattr.setxattr(resPath, "WebDAV:{http:%2F%2Ftwistedmatrix.com%2Fxml_namespace%2Fdav%2F}getcontentmd5", md5value)
++                xattr.setxattr(resPath, "user.{http:%2F%2Ftwistedmatrix.com%2Fxml_namespace%2Fdav%2F}getcontentmd5", md5value)
+ 
+                 collectionUpdated = True
+ 
+@@ -164,7 +164,7 @@
+         if collectionUpdated:
+             ctagValue = "<?xml version='1.0' encoding='UTF-8'?>\r\n<getctag xmlns='http://calendarserver.org/ns/'>%s</getctag>\r\n" % (str(datetime.datetime.now()),)
+             ctagValue = zlib.compress(ctagValue)
+-            xattr.setxattr(calPath, "WebDAV:{http:%2F%2Fcalendarserver.org%2Fns%2F}getctag", ctagValue)
++            xattr.setxattr(calPath, "user.{http:%2F%2Fcalendarserver.org%2Fns%2F}getctag", ctagValue)
+ 
+         return errorOccurred
+ 
+@@ -194,7 +194,7 @@
+                 # __uids__/<guid> form
+                 if cal == "inbox":
+                     for attr, value in xattr.xattr(calPath).iteritems():
+-                        if attr == "WebDAV:{urn:ietf:params:xml:ns:caldav}calendar-free-busy-set":
++                        if attr == "user.{urn:ietf:params:xml:ns:caldav}calendar-free-busy-set":
+                             value = updateFreeBusySet(value, directory)
+                             if value is not None:
+                                 # Need to write the xattr back to disk
--- calendarserver-2.4.dfsg.orig/debian/patches/nssdirectory.patch
+++ calendarserver-2.4.dfsg/debian/patches/nssdirectory.patch
@@ -0,0 +1,316 @@
+Index: calendarserver-2.4.dfsg/conf/caldavd.plist
+===================================================================
+--- calendarserver-2.4.dfsg.orig/conf/caldavd.plist	2010-08-24 21:17:17.000000000 +0530
++++ calendarserver-2.4.dfsg/conf/caldavd.plist	2010-08-24 21:50:01.000000000 +0530
+@@ -158,6 +158,39 @@
+     </dict>
+      -->
+ 
++    <!-- NSS Directory Service -->
++    <!-- Groups starting with groupPrefix are considered calendarserver groups -->
++    <!-- Don't treat user id's smaller than firstValidUid as calendarserver users -->
++    <!-- Don't treat group id's smaller than firstValidGid as calendarserver groups -->
++    <!-- use shortName@mailDomain as calender user mail addresses -->
++    <!--
++    <key>DirectoryService</key>
++    <dict>
++      <key>type</key>
++      <string>twistedcaldav.directory.nss.NssDirectoryService</string>
++
++      <key>params</key>
++      <dict>
++        <key>realmName</key>
++        <string>Test Realm</string>
++        <key>groupPrefix</key>
++        <string>caldavd-</string>
++        <key>firstValidUid</key>
++        <integer>1000</integer>
++        <key>lastValidUid</key>
++        <integer>65533</integer>
++        <key>firstValidGid</key>
++        <integer>1000</integer>
++        <key>lastValidGid</key>
++        <integer>65533</integer>
++        <key>mailDomain</key>
++        <string>example.com</string>
++        <key>cacheTimeout</key>
++        <integer>30</integer>
++      </dict>
++    </dict>
++     -->
++
+     <!--
+         Special principals
+ 
+Index: calendarserver-2.4.dfsg/twistedcaldav/directory/nss.py
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ calendarserver-2.4.dfsg/twistedcaldav/directory/nss.py	2010-08-24 21:51:04.000000000 +0530
+@@ -0,0 +1,267 @@
++##
++# vim: set fileencoding=utf-8 :
++# Copyright (c) 2008 Guido Guenther <agx@sigxcpu.org>
++#
++# Licensed under the Apache License, Version 2.0 (the "License");
++# you may not use this file except in compliance with the License.
++# You may obtain a copy of the License at
++#
++# http://www.apache.org/licenses/LICENSE-2.0
++#
++# Unless required by applicable law or agreed to in writing, software
++# distributed under the License is distributed on an "AS IS" BASIS,
++# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++# See the License for the specific language governing permissions and
++# limitations under the License.
++#
++##
++
++"""
++NSS Directory service interfaces.
++
++Uses libc's Name Service Switch for user and groups (/etc/nsswitch.conf).
++"""
++
++__all__ = [
++    "NssDirectoryService",
++]
++
++from twistedcaldav.directory.cachingdirectory import CachingDirectoryService,\
++    CachingDirectoryRecord
++from twisted.cred.credentials import UsernamePassword
++from twistedcaldav.scheduling.cuaddress import normalizeCUAddr
++from twisted.python import log
++import pwd, grp, socket
++import PAM
++
++class NsSwitch(object):
++    """Simple interface to the nsswitch calls"""
++
++    def get_user(self, username):
++        try:
++            return pwd.getpwnam(username)
++        except KeyError:
++            return None
++
++    def get_group(self, groupname):
++        try:
++            return grp.getgrnam(groupname)
++        except KeyError:
++            return None
++
++    def get_users(self):
++        return pwd.getpwall()
++
++    def get_groups(self):
++        return grp.getgrall()
++
++
++class NssDirectoryService(CachingDirectoryService):
++    """
++    Nss based Directory Service of L{IDirectoryService}
++    """
++
++    baseGUID = "8EFFFAF1-5221-4813-B971-58506B963573"
++
++    def __repr__(self):
++        return "<%s %r>" % (self.__class__.__name__, self.realmName)
++
++    # Defaults are in twistedcaldav.config:
++    def __init__(self, params, dosetup=True):
++        """
++        @param params: a dictionary containing the following keys:
++            cacheTimeout, realmName, groupPrefix, mailDomain, firstValidUid,
++            lastValidUid, firstValidGid, lastValidGid
++        @param dosetup: if C{True} then the directory records are initialized,
++                        if C{False} they are not.
++                        This should only be set to C{False} when doing unit tests.
++        """
++
++        defaults = {
++            "realmName": "Test Realm",
++            # we only consider groups starting with:
++            "groupPrefix": "caldavd-",
++            # dont set calendarUserAdresses by default
++            "mailDomain": None,
++            # exclude system users and nobody by "default":
++            "firstValidUid": 1000,
++            "lastValidUid": 65533,
++            "firstValidGid": 1000,
++            "lastValidGid": 65533,
++            "cacheTimeout": 30,
++        }
++        ignored = None
++        params = self.getParams(params, defaults, ignored)
++
++        super(NssDirectoryService, self).__init__(params['cacheTimeout'])
++
++        self.nsswitch = NsSwitch()
++        self.realmName = params["realmName"]
++        self.mailDomain = params["mailDomain"]
++        self.groupPrefix = params["groupPrefix"]
++        self.first_valid_uid = params["firstValidUid"]
++        self.first_valid_gid = params["firstValidGid"]
++        self.last_valid_uid = params["lastValidUid"]
++        self.last_valid_gid = params["lastValidGid"]
++
++    def recordTypes(self):
++        recordTypes = (
++            self.recordType_users,
++            self.recordType_groups,
++        )
++        return recordTypes
++
++    def _isValidUid(self, uid):
++        if uid >= self.first_valid_uid and uid <= self.last_valid_uid:
++            return True
++
++    def _isValidGid(self, gid):
++        if gid >= self.first_valid_gid and gid <= self.last_valid_gid:
++            return True
++
++    def queryDirectory(self, recordTypes, indexType, indexKey):
++        self.log_debug("Querying directory for recordTypes %s, "
++                       "indexType %s and indexKey %s" %
++                       (recordTypes, indexType, indexKey),
++                       system="NssDirectoryService")
++
++        def _recordWithGUID(recordType, guid):
++            # Code has to be written to query on GUID
++            pass
++
++        def _recordWithShortName(recordType, shortName):
++            record = None
++            if recordType == self.recordType_users:
++                result = self.nsswitch.get_user(shortName)
++                if result and self._isValidUid(result[2]):
++                    record = NssUserRecord(
++                                service = self,
++                                userName = result[0],
++                                gecos = result[4],
++                             )
++            elif recordType == self.recordType_groups:
++                result = self.nsswitch.get_group(self.groupPrefix + shortName)
++                if result and self._isValidGid(result[2]):
++                    record = NssGroupRecord(
++                                service = self,
++                                groupName = result[0],
++                                members = result[3]
++                             )
++            return record
++
++        for recordType in recordTypes:
++            record = None
++            if indexType == self.INDEX_TYPE_GUID:
++                record = _recordWithGUID(recordType, indexKey)
++            elif indexType == self.INDEX_TYPE_SHORTNAME:
++                record = _recordWithShortName(recordType, indexKey)
++            elif indexType == self.INDEX_TYPE_CUA:
++                address = normalizeCUAddr(indexKey)
++                if address.startswith("urn:uuid:"):
++                    guid = address[9:]
++                    record = _recordWithGUID(recordType, guid)
++                elif address.startswith("mailto:") and \
++                     address.endswith("@"+self.mailDomain):
++                    shortName = address[7:].partition("@")[0]
++                    record = _recordWithShortName(recordType, shortName)
++            elif indexType == self.INDEX_TYPE_AUTHID:
++                pass
++
++            if record:
++                self.recordCacheForType(recordType).addRecord(
++                        record, indexType, indexKey
++                )
++
++
++class NssDirectoryRecord(CachingDirectoryRecord):
++    """
++    Nss Directory Record
++    """
++    def __init__(self, service, recordType, shortNames,
++                 fullName=None, calendarUserAddresses=set()):
++        super(NssDirectoryRecord, self).__init__(
++            service               = service,
++            recordType            = recordType,
++            guid                  = None,
++            shortNames            = shortNames,
++            fullName              = fullName,
++            calendarUserAddresses = calendarUserAddresses,
++        )
++
++
++class NssUserRecord(NssDirectoryRecord):
++    """
++    NSS Users implementation of L{IDirectoryRecord}.
++    """
++    def __init__(self, service, userName, gecos):
++        recordType = service.recordType_users
++        shortNames = (userName,)
++        fullName = gecos.split(",",1)[0]
++        calendarUserAddresses = set()
++        if service.mailDomain:
++            calendarUserAddresses.add("mailto:%s@%s" %
++                                      (userName, service.mailDomain))
++        super(NssUserRecord, self).__init__(service, recordType, shortNames,
++                                            fullName, calendarUserAddresses)
++
++    def groups(self):
++        for result in self.service.nsswitch.get_groups():
++            if self.service._isValidGid(result[2]) and \
++               result[0].startswith(self.service.groupPrefix) and \
++               self.shortNames[0] in result[3]:
++                yield self.service.recordWithShortName(
++                        self.service.recordType_groups,
++                        result[0].replace(self.service.groupPrefix,'',1)
++                      )
++
++    def verifyCredentials(self, credentials):
++        if isinstance(credentials, UsernamePassword):
++            # Check that the username supplied matches the shortName
++            # (The DCS might already enforce this constraint, not sure)
++            if credentials.username not in self.shortNames:
++                return False
++
++            # Check cached password
++            try:
++                if credentials.password == self.password:
++                    return True
++            except AttributeError:
++                pass
++
++            # Authenticate against PAM
++            def pam_conv(auth, query_list, userData):
++                return [(credentials.password, 0)]
++
++            auth = PAM.pam()
++            auth.start("caldav")
++            auth.set_item(PAM.PAM_USER, credentials.username)
++            auth.set_item(PAM.PAM_CONV, pam_conv)
++            try:
++                auth.authenticate()
++            except PAM.error, resp:
++                return False
++            else:
++                # Cache the password to avoid future DS queries
++                self.password = credentials.password
++                return True
++
++        return super(NssUserRecord, self).verifyCredentials(credentials)
++
++class NssGroupRecord(NssDirectoryRecord):
++    """
++    NSS Groups implementation of L{IDirectoryRecord}.
++    """
++    def __init__(self, service, groupName, members=()):
++        recordType = service.recordType_groups
++        shortNames  = (groupName.replace(service.groupPrefix,'',1),)
++        super(NssGroupRecord, self).__init__(service, recordType, shortNames)
++        self._members = members
++
++    def members(self):
++        for shortName in self._members:
++            yield self.service.recordWithShortName(
++                    self.service.recordType_users,
++                    shortName
++                  )
++
++# vim:et:ts=4:sw=4:et:sts=4:ai:set list listchars=tab\:»·,trail\:·:
--- calendarserver-2.4.dfsg.orig/debian/patches/series
+++ calendarserver-2.4.dfsg/debian/patches/series
@@ -0,0 +1,5 @@
+nssdirectory.patch
+ldapdirectory.patch
+paths.diff
+linux-xattr-fix.patch
+secure-python-path.patch