NSS Directory Service. This had originally been distributed as a patch in the
calendarserver package.
--- /dev/null
+++ b/twext/who/nss.py
@@ -0,0 +1,201 @@
+##
+# Copyright (c) 2016 Rahul Amaram <amaramrahul@users.sourceforge.net>
+#
+# 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).
+"""
+
+import pwd
+import grp
+import PAM
+from time import time
+from uuid import UUID
+
+from twisted.internet.defer import succeed
+from twext.python.log import Logger
+from twistedcaldav.directory.util import uuidFromName
+from .idirectory import (
+    RecordType,
+    FieldName
+)
+from .index import (
+    DirectoryService,
+    DirectoryRecord,
+    FieldName as IndexFieldName,
+)
+from .util import ConstantsContainer
+
+__all__ = [
+    "NssDirectoryService",
+]
+
+# Logger
+log = Logger()
+
+
+def _generateUID(serviceGUID, recordType, shortName):
+    return unicode(uuidFromName(serviceGUID,
+                                "%s:%s" % (recordType, shortName)),
+                   "utf-8")
+
+
+class NssDirectoryService(DirectoryService):
+
+    # Supported record types
+    recordType = ConstantsContainer(
+        (RecordType.user, RecordType.group)
+    )
+
+    _baseGUID = "8EFFFAF1-5221-4813-B971-58506B963573"
+
+    _lastRefresh = 0
+
+    def __init__(self, params):
+        """
+        @param params: a dictionary containing the following keys:
+            realmName, groupPrefix, mailDomain, firstValidUid, lastValidUid,
+            firstValidGid, lastValidGid, refreshIntervalThreshold
+        """
+        self.mailDomain = params["mailDomain"]
+        self.groupPrefix = params["groupPrefix"]
+        self.firstValidUid = params["firstValidUid"]
+        self.firstValidGid = params["firstValidGid"]
+        self.lastValidUid = params["lastValidUid"]
+        self.lastValidGid = params["lastValidGid"]
+        self.refreshIntervalThreshold = params["refreshIntervalThreshold"]
+        self.guid = uuidFromName(self._baseGUID, params["realmName"])
+
+        DirectoryService.__init__(self, realmName=params["realmName"])
+
+    def flush(self):
+        DirectoryService.flush(self)
+        _lastRefresh = 0
+
+    def _isValidUid(self, uid):
+        if uid >= self.firstValidUid and uid <= self.lastValidUid:
+            return True
+
+    def _isValidGid(self, gid):
+        if gid >= self.firstValidGid and gid <= self.lastValidGid:
+            return True
+
+    def loadRecords(self):
+        now = time()
+        if now - self._lastRefresh <= self.refreshIntervalThreshold:
+            return
+
+        log.info("Loading and indexing NSS records")
+        users = set()
+        groups = set()
+        records = set()
+        for result in pwd.getpwall():
+            if self._isValidUid(result[2]):
+                record = NssUserRecord(
+                            service=self,
+                            userName=result[0],
+                            gecos=result[4],
+                            )
+                records.add(record)
+                users.add(result[0])
+        for result in grp.getgrall():
+            if result[0].startswith(self.groupPrefix) and \
+                    self._isValidGid(result[2]):
+                record = NssGroupRecord(
+                            service=self,
+                            groupName=result[0],
+                            members=result[3]
+                            )
+                records.add(record)
+                groups.add(result[0])
+
+        log.debug("Processed NSS Users: {}".format(users))
+        log.debug("Processed NSS Groups: {}".format(groups))
+
+        # Store results
+        self.flush()
+        self.indexRecords(records)
+        _lastRefresh = now
+
+
+class NssUserRecord(DirectoryRecord):
+    """
+    NSS Users implementation of L{IDirectoryRecord}.
+    """
+    def __init__(self, service, userName, gecos):
+        uid = _generateUID(service.guid, "users", userName)
+        guid = UUID(uid)
+        shortNames = (unicode(userName, "utf-8"),)
+        fullNames = (unicode(gecos.split(",", 1)[0], "utf-8"),)
+        emailAddresses = set()
+        if service.mailDomain:
+            emailAddresses.add(unicode("%s@%s" %
+                                       (userName, service.mailDomain), "utf-8"))
+        log.debug("Creating user record with uid: %r, guid: %r, "
+                  "shortNames: %r, fullNames: %r, emailAddresses: %r" %
+                  (uid, guid, shortNames, fullNames, emailAddresses))
+        super(NssUserRecord, self).__init__(service,  dict([
+            (FieldName.recordType, service.recordType.user),
+            (FieldName.uid, uid),
+            (FieldName.guid, guid),
+            (FieldName.shortNames, shortNames),
+            (FieldName.fullNames, fullNames),
+            (FieldName.emailAddresses, emailAddresses)
+            ])
+        )
+
+    def verifyPlaintextPassword(self, password):
+        # Authenticate against PAM
+        def pam_conv(auth, query_list, userData):
+            return [(password, 0)]
+
+        auth = PAM.pam()
+        auth.start("caldav")
+        auth.set_item(PAM.PAM_USER, self.shortNames[0])
+        auth.set_item(PAM.PAM_CONV, pam_conv)
+        try:
+            auth.authenticate()
+        except PAM.error, resp:
+            return succeed(False)
+        else:
+            return succeed(True)
+
+
+class NssGroupRecord(DirectoryRecord):
+    """
+    NSS Groups implementation of L{IDirectoryRecord}.
+    """
+    def __init__(self, service, groupName, members=()):
+        groupNameWithoutPrefix = groupName.replace(service.groupPrefix, '', 1)
+        uid = _generateUID(service.guid, "groups", groupNameWithoutPrefix)
+        guid = UUID(uid)
+        shortNames = (unicode(groupNameWithoutPrefix, "utf-8"),)
+        memberUIDs = tuple([_generateUID(service.guid, "users", userName)
+                            for userName in members])
+        log.debug("Creating group record with uid: %r, guid: %r, "
+                  "shortNames: %r, memberUIDs: %r" %
+                  (uid, guid, shortNames, memberUIDs))
+        super(NssGroupRecord, self).__init__(service, dict([
+            (FieldName.recordType, service.recordType.group),
+            (FieldName.uid, uid),
+            (FieldName.guid, guid),
+            (FieldName.shortNames, shortNames),
+            (IndexFieldName.memberUIDs, memberUIDs)
+            ])
+        )
+
