From 698dfefdad8ad8f04d4bdc35204bd344e812f213 Mon Sep 17 00:00:00 2001
From: Simo Sorce <simo@redhat.com>
Date: Mon, 1 Feb 2016 07:35:17 -0500
Subject: [PATCH 11/15] Secrets: Add encryption at rest

Generates a master key file if it doesn't exist and encrypts secrets using the
master key contained in the file.

Resolves:
https://fedorahosted.org/sssd/ticket/XXXX
---
 Makefile.am                             |  14 +-
 po/ca.po                                | 690 ++++++++++++++++----------------
 src/responder/secrets/local.c           | 191 +++++++--
 src/responder/secrets/secsrv_local.h    |   2 +-
 src/util/crypto/libcrypto/crypto_nite.c | 226 +++++++++++
 src/util/crypto/nss/nss_crypto.h        |  67 ++++
 src/util/crypto/nss/nss_nite.c          | 245 ++++++++++++
 src/util/crypto/nss/nss_obfuscate.c     | 214 +---------
 src/util/crypto/nss/nss_util.c          | 211 +++++++++-
 src/util/crypto/nss/nss_util.h          |   1 +
 src/util/crypto/sss_crypto.c            |  66 +++
 src/util/crypto/sss_crypto.h            |  37 ++
 12 files changed, 1396 insertions(+), 568 deletions(-)
 create mode 100644 src/util/crypto/libcrypto/crypto_nite.c
 create mode 100644 src/util/crypto/nss/nss_crypto.h
 create mode 100644 src/util/crypto/nss/nss_nite.c
 create mode 100644 src/util/crypto/sss_crypto.c

diff --git a/Makefile.am b/Makefile.am
index fd9f493bedf319a0c38d224d8d7e1fc981f1a06d..1e1ebcef72e8a8eea1c079b6ee0faeb763131df4 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -692,7 +692,8 @@ dist_noinst_HEADERS = \
 
 
 if HAVE_NSS
-    dist_noinst_HEADERS += src/util/crypto/nss/nss_util.h
+    dist_noinst_HEADERS += src/util/crypto/nss/nss_util.h \
+                           src/util/crypto/nss/nss_crypto.h
 endif
 
 SSSD_DOCS = \
@@ -751,7 +752,10 @@ if HAVE_NSS
                         src/util/crypto/nss/nss_hmac_sha1.c \
                         src/util/crypto/nss/nss_sha512crypt.c \
                         src/util/crypto/nss/nss_obfuscate.c \
-                        src/util/crypto/nss/nss_util.c
+                        src/util/crypto/nss/nss_nite.c \
+                        src/util/crypto/nss/nss_util.c \
+			src/util/crypto/sss_crypto.c \
+			$(NULL)
     SSS_CRYPT_CFLAGS = $(NSS_CFLAGS)
     SSS_CRYPT_LIBS = $(NSS_LIBS)
 
@@ -769,7 +773,10 @@ else
     SSS_CRYPT_SOURCES = src/util/crypto/libcrypto/crypto_base64.c \
                         src/util/crypto/libcrypto/crypto_hmac_sha1.c \
                         src/util/crypto/libcrypto/crypto_sha512crypt.c \
-                        src/util/crypto/libcrypto/crypto_obfuscate.c
+                        src/util/crypto/libcrypto/crypto_obfuscate.c \
+                        src/util/crypto/libcrypto/crypto_nite.c \
+			src/util/crypto/sss_crypto.c \
+			$(NULL)
     SSS_CRYPT_CFLAGS = $(CRYPTO_CFLAGS)
     SSS_CRYPT_LIBS = $(CRYPTO_LIBS)
 
@@ -2653,6 +2660,7 @@ test_krb5_wait_queue_LDADD = \
 
 test_cert_utils_SOURCES = \
     src/tests/cmocka/test_cert_utils.c \
+    src/util/util.c \
     $(NULL)
 test_cert_utils_CFLAGS = \
     $(AM_CFLAGS) \
diff --git a/po/ca.po b/po/ca.po
index b9d249f6056d2e0d82ddb2420fe0894ba0e64d16..07dfd17c66cb3f73004e4b1bcd904eda22dc3671 100644
--- a/po/ca.po
+++ b/po/ca.po
@@ -1,7 +1,7 @@
 # SOME DESCRIPTIVE TITLE.
 # Copyright (C) YEAR Red Hat, Inc.
 # This file is distributed under the same license as the PACKAGE package.
-# 
+#
 # Translators:
 # muzzol <muzzol@gmail.com>, 2012
 # muzzol <muzzol@gmail.com>, 2012
@@ -13,15 +13,15 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: sssd-devel@lists.fedorahosted.org\n"
-"POT-Creation-Date: 2015-06-22 11:41+0200\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
+"POT-Creation-Date: 2015-09-30 11:59+0200\n"
 "PO-Revision-Date: 2015-09-29 10:18-0400\n"
 "Last-Translator: Robert Antoni Buj Gelonch <rbuj@fedoraproject.org>\n"
-"Language-Team: Catalan (http://www.transifex.com/projects/p/sssd/language/ca/"
-")\n"
+"Language-Team: Catalan (http://www.transifex.com/projects/p/sssd/language/"
+"ca/)\n"
 "Language: ca\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
 "X-Generator: Zanata 3.7.2\n"
 
@@ -59,8 +59,7 @@ msgstr "L'ordre per iniciar el servei"
 
 #: src/config/SSSDConfig/__init__.py.in:50
 msgid "Number of times to attempt connection to Data Providers"
-msgstr ""
-"El nombre de vegaders per intentar la connexió als proveïdors de dades"
+msgstr "El nombre de vegaders per intentar la connexió als proveïdors de dades"
 
 #: src/config/SSSDConfig/__init__.py.in:51
 msgid "The number of file descriptors that may be opened by this responder"
@@ -121,7 +120,7 @@ msgstr ""
 "entrades de la memòria auxiliar (en segons)"
 
 #: src/config/SSSDConfig/__init__.py.in:67
-#: src/config/SSSDConfig/__init__.py.in:97
+#: src/config/SSSDConfig/__init__.py.in:99
 msgid "Negative cache timeout length (seconds)"
 msgstr ""
 "La durada del temps d'expiració de la memòria auxiliar, negativa (en segons)"
@@ -245,17 +244,25 @@ msgstr ""
 msgid "Message printed when user account is expired."
 msgstr "El missatge que es mostra quan venç el compte de l'usuari."
 
-#: src/config/SSSDConfig/__init__.py.in:94
+#: src/config/SSSDConfig/__init__.py.in:92
+msgid "How many seconds will pam_sss wait for p11_child to finish"
+msgstr ""
+
+#: src/config/SSSDConfig/__init__.py.in:95
 msgid "Whether to evaluate the time-based attributes in sudo rules"
 msgstr "Si s'avaluen els atributs basats en temps a les regles sudo"
 
-#: src/config/SSSDConfig/__init__.py.in:100
+#: src/config/SSSDConfig/__init__.py.in:96
+msgid "If true, SSSD will switch back to lower-wins ordering logic"
+msgstr ""
+
+#: src/config/SSSDConfig/__init__.py.in:102
 msgid "Whether to hash host names and addresses in the known_hosts file"
 msgstr ""
 "Si s'utilitzen els algoritmes hash als noms i adreces dels amfitrions al "
 "fitxer known_hosts"
 
-#: src/config/SSSDConfig/__init__.py.in:101
+#: src/config/SSSDConfig/__init__.py.in:103
 msgid ""
 "How many seconds to keep a host in the known_hosts file after its host keys "
 "were requested"
@@ -264,558 +271,567 @@ msgstr ""
 "s'hagi sol·licitat la seva clau"
 
 #: src/config/SSSDConfig/__init__.py.in:104
+#, fuzzy
+msgid "Path to storage of trusted CA certificates"
+msgstr "Fitxer que conté els certificats CA"
+
+#: src/config/SSSDConfig/__init__.py.in:107
 msgid "List of UIDs or user names allowed to access the PAC responder"
 msgstr ""
 "La llista dels UID o dels noms d'usuari que poden accedir al contestador del "
 "PAC"
 
-#: src/config/SSSDConfig/__init__.py.in:107
+#: src/config/SSSDConfig/__init__.py.in:110
 msgid "List of UIDs or user names allowed to access the InfoPipe responder"
 msgstr ""
 "La llista dels UID o dels noms d'usuari que poden accedir al contestador de "
 "l'InfoPipe"
 
-#: src/config/SSSDConfig/__init__.py.in:108
+#: src/config/SSSDConfig/__init__.py.in:111
 msgid "List of user attributes the InfoPipe is allowed to publish"
 msgstr "La llista dels atributs de l'usuari que l'InfoPipe pot publicar"
 
-#: src/config/SSSDConfig/__init__.py.in:111
+#: src/config/SSSDConfig/__init__.py.in:114
 msgid "Identity provider"
 msgstr "Proveïdor d'identitat"
 
-#: src/config/SSSDConfig/__init__.py.in:112
+#: src/config/SSSDConfig/__init__.py.in:115
 msgid "Authentication provider"
 msgstr "Proveïdor d'autenticació"
 
-#: src/config/SSSDConfig/__init__.py.in:113
+#: src/config/SSSDConfig/__init__.py.in:116
 msgid "Access control provider"
 msgstr "Proveïdor de control d'accés"
 
-#: src/config/SSSDConfig/__init__.py.in:114
+#: src/config/SSSDConfig/__init__.py.in:117
 msgid "Password change provider"
 msgstr "Proveïdor de canvi de contrasenya"
 
-#: src/config/SSSDConfig/__init__.py.in:115
+#: src/config/SSSDConfig/__init__.py.in:118
 msgid "SUDO provider"
 msgstr "Proveïdor de SUDO"
 
-#: src/config/SSSDConfig/__init__.py.in:116
+#: src/config/SSSDConfig/__init__.py.in:119
 msgid "Autofs provider"
 msgstr "Proveïdor d'Autofs"
 
-#: src/config/SSSDConfig/__init__.py.in:117
+#: src/config/SSSDConfig/__init__.py.in:120
 msgid "Session-loading provider"
 msgstr "Proveïdor de càrrega de sessió"
 
-#: src/config/SSSDConfig/__init__.py.in:118
+#: src/config/SSSDConfig/__init__.py.in:121
 msgid "Host identity provider"
 msgstr "Proveïdor d'identitat d'amfitrions"
 
-#: src/config/SSSDConfig/__init__.py.in:121
+#: src/config/SSSDConfig/__init__.py.in:124
 msgid "Minimum user ID"
 msgstr "ID mínim d'usuari"
 
-#: src/config/SSSDConfig/__init__.py.in:122
+#: src/config/SSSDConfig/__init__.py.in:125
 msgid "Maximum user ID"
 msgstr "ID màxim d'usuari"
 
-#: src/config/SSSDConfig/__init__.py.in:123
+#: src/config/SSSDConfig/__init__.py.in:126
 msgid "Enable enumerating all users/groups"
 msgstr "Activa l'enumeració de tots els usuaris/grups"
 
-#: src/config/SSSDConfig/__init__.py.in:124
+#: src/config/SSSDConfig/__init__.py.in:127
 msgid "Cache credentials for offline login"
-msgstr ""
-"Credencials en memòria auxiliar per als inicis de sessió fora de línia"
+msgstr "Credencials en memòria auxiliar per als inicis de sessió fora de línia"
 
-#: src/config/SSSDConfig/__init__.py.in:125
+#: src/config/SSSDConfig/__init__.py.in:128
 msgid "Store password hashes"
 msgstr "Emmagatzema els codis hash de les contrasenyes"
 
-#: src/config/SSSDConfig/__init__.py.in:126
+#: src/config/SSSDConfig/__init__.py.in:129
 msgid "Display users/groups in fully-qualified form"
 msgstr "Mostra els usuaris/grups en format plenament qualificat"
 
-#: src/config/SSSDConfig/__init__.py.in:127
+#: src/config/SSSDConfig/__init__.py.in:130
 msgid "Don't include group members in group lookups"
 msgstr "No incloure als membres dels grups en la recerca del grup"
 
-#: src/config/SSSDConfig/__init__.py.in:128
-#: src/config/SSSDConfig/__init__.py.in:135
-#: src/config/SSSDConfig/__init__.py.in:136
-#: src/config/SSSDConfig/__init__.py.in:137
+#: src/config/SSSDConfig/__init__.py.in:131
 #: src/config/SSSDConfig/__init__.py.in:138
 #: src/config/SSSDConfig/__init__.py.in:139
 #: src/config/SSSDConfig/__init__.py.in:140
+#: src/config/SSSDConfig/__init__.py.in:141
+#: src/config/SSSDConfig/__init__.py.in:142
+#: src/config/SSSDConfig/__init__.py.in:143
 msgid "Entry cache timeout length (seconds)"
 msgstr ""
 "La durada del temps d'expiració de les entrades de la memòria auxiliar (en "
 "segons)"
 
-#: src/config/SSSDConfig/__init__.py.in:129
+#: src/config/SSSDConfig/__init__.py.in:132
 msgid ""
 "Restrict or prefer a specific address family when performing DNS lookups"
 msgstr ""
 "Restringeix o prefereix una família específica d'adreces quan es realitzi la "
 "recerca del DNS"
 
-#: src/config/SSSDConfig/__init__.py.in:130
+#: src/config/SSSDConfig/__init__.py.in:133
 msgid "How long to keep cached entries after last successful login (days)"
 msgstr ""
 "Quant de temps s'han de mantenir les entrades en la memòria auxiliar després "
 "de l'últim inici de sessió reeixit (en dies)"
 
-#: src/config/SSSDConfig/__init__.py.in:131
+#: src/config/SSSDConfig/__init__.py.in:134
 msgid "How long to wait for replies from DNS when resolving servers (seconds)"
 msgstr ""
 "Temps d'expiració per a les respostes del DNS en la resolució dels servidors "
 "(en segons)"
 
-#: src/config/SSSDConfig/__init__.py.in:132
+#: src/config/SSSDConfig/__init__.py.in:135
 msgid "The domain part of service discovery DNS query"
 msgstr "La part de domini de la consulta DNS del descobriment del servei"
 
-#: src/config/SSSDConfig/__init__.py.in:133
+#: src/config/SSSDConfig/__init__.py.in:136
 msgid "Override GID value from the identity provider with this value"
 msgstr "Substitueix el valor GID del proveïdor d'identitat amb aquest valor"
 
-#: src/config/SSSDConfig/__init__.py.in:134
+#: src/config/SSSDConfig/__init__.py.in:137
 msgid "Treat usernames as case sensitive"
 msgstr "Distingeix entre majúscules i minúscules als noms d'usuari"
 
-#: src/config/SSSDConfig/__init__.py.in:141
+#: src/config/SSSDConfig/__init__.py.in:144
 msgid "How often should expired entries be refreshed in background"
 msgstr "Amb quina freqüència les entrades vençudes s'actualitzen al rerefons"
 
-#: src/config/SSSDConfig/__init__.py.in:142
+#: src/config/SSSDConfig/__init__.py.in:145
 msgid "Whether to automatically update the client's DNS entry"
 msgstr "Si s'actualitza automàticament l'entrada DNS del client"
 
-#: src/config/SSSDConfig/__init__.py.in:143
-#: src/config/SSSDConfig/__init__.py.in:159
+#: src/config/SSSDConfig/__init__.py.in:146
+#: src/config/SSSDConfig/__init__.py.in:164
 msgid "The TTL to apply to the client's DNS entry after updating it"
-msgstr ""
-"El TTL per aplicar a l'entrada DNS del client després d'actualitzar-ho"
+msgstr "El TTL per aplicar a l'entrada DNS del client després d'actualitzar-ho"
 
-#: src/config/SSSDConfig/__init__.py.in:144
-#: src/config/SSSDConfig/__init__.py.in:160
+#: src/config/SSSDConfig/__init__.py.in:147
+#: src/config/SSSDConfig/__init__.py.in:165
 msgid "The interface whose IP should be used for dynamic DNS updates"
 msgstr ""
 "La interfície amb la IP que s'hauria d'utilitzar per a les actualitzacions "
 "dinàmiques DNS"
 
-#: src/config/SSSDConfig/__init__.py.in:145
+#: src/config/SSSDConfig/__init__.py.in:148
 msgid "How often to periodically update the client's DNS entry"
 msgstr "Cada quant s'actualitzarà automàticament l'entrada DNS del client"
 
-#: src/config/SSSDConfig/__init__.py.in:146
+#: src/config/SSSDConfig/__init__.py.in:149
 msgid "Whether the provider should explicitly update the PTR record as well"
 msgstr ""
 
-#: src/config/SSSDConfig/__init__.py.in:147
+#: src/config/SSSDConfig/__init__.py.in:150
 msgid "Whether the nsupdate utility should default to using TCP"
 msgstr "Si la utilitat nsupdate per defecte ha d'utilitzar TCP"
 
-#: src/config/SSSDConfig/__init__.py.in:148
+#: src/config/SSSDConfig/__init__.py.in:151
 msgid "What kind of authentication should be used to perform the DNS update"
 msgstr ""
 "Quin tipus d'autentificació s'ha d'utilitzar per realitzar l'actualització "
 "del DNS"
 
-#: src/config/SSSDConfig/__init__.py.in:149
+#: src/config/SSSDConfig/__init__.py.in:152
+#, fuzzy
+msgid "Override the DNS server used to perform the DNS update"
+msgstr ""
+"Quin tipus d'autentificació s'ha d'utilitzar per realitzar l'actualització "
+"del DNS"
+
+#: src/config/SSSDConfig/__init__.py.in:153
 msgid "Control enumeration of trusted domains"
 msgstr "Enumeració de control dels amfitrions de confiança"
 
-#: src/config/SSSDConfig/__init__.py.in:150
+#: src/config/SSSDConfig/__init__.py.in:154
 msgid "How often should subdomains list be refreshed"
 msgstr "Amb quina freqüència s'ha de refrescar la llista dels subdominis"
 
-#: src/config/SSSDConfig/__init__.py.in:151
+#: src/config/SSSDConfig/__init__.py.in:155
 msgid "List of options that should be inherited into a subdomain"
 msgstr ""
 
-#: src/config/SSSDConfig/__init__.py.in:154
+#: src/config/SSSDConfig/__init__.py.in:156
+msgid "How long can cached credentials be used for cached authentication"
+msgstr ""
+
+#: src/config/SSSDConfig/__init__.py.in:159
 msgid "IPA domain"
 msgstr "Domini IPA"
 
-#: src/config/SSSDConfig/__init__.py.in:155
+#: src/config/SSSDConfig/__init__.py.in:160
 msgid "IPA server address"
 msgstr "Adreça del servidor IPA"
 
-#: src/config/SSSDConfig/__init__.py.in:156
+#: src/config/SSSDConfig/__init__.py.in:161
 msgid "Address of backup IPA server"
 msgstr "Adreça del servidor IPA de reserva "
 
-#: src/config/SSSDConfig/__init__.py.in:157
+#: src/config/SSSDConfig/__init__.py.in:162
 msgid "IPA client hostname"
 msgstr "Nom d'amfitrió del client IPA"
 
-#: src/config/SSSDConfig/__init__.py.in:158
+#: src/config/SSSDConfig/__init__.py.in:163
 msgid "Whether to automatically update the client's DNS entry in FreeIPA"
 msgstr "Si s'actualitza automàticament l'entrada DNS del client a FreeIPA"
 
-#: src/config/SSSDConfig/__init__.py.in:161
+#: src/config/SSSDConfig/__init__.py.in:166
 msgid "Search base for HBAC related objects"
 msgstr "Base de cerca pels objectes HBAC"
 
-#: src/config/SSSDConfig/__init__.py.in:162
+#: src/config/SSSDConfig/__init__.py.in:167
 msgid ""
 "The amount of time between lookups of the HBAC rules against the IPA server"
 msgstr ""
 "Quantitat de temps entre recerques de les regles HBAC contra el servidor IPA"
 
-#: src/config/SSSDConfig/__init__.py.in:163
+#: src/config/SSSDConfig/__init__.py.in:168
 msgid ""
 "The amount of time in seconds between lookups of the SELinux maps against "
 "the IPA server"
 msgstr ""
 
-#: src/config/SSSDConfig/__init__.py.in:164
+#: src/config/SSSDConfig/__init__.py.in:169
 msgid "If set to false, host argument given by PAM will be ignored"
 msgstr ""
 "Si s'estableix a fals, s'ignorarà l'argument de l'amfitrió proporcionat amb "
 "PAM"
 
-#: src/config/SSSDConfig/__init__.py.in:165
+#: src/config/SSSDConfig/__init__.py.in:170
 msgid "The automounter location this IPA client is using"
 msgstr ""
 "La ubicació del muntador automàtic que aquest client IPA està utilitzant"
 
-#: src/config/SSSDConfig/__init__.py.in:166
+#: src/config/SSSDConfig/__init__.py.in:171
 msgid "Search base for object containing info about IPA domain"
 msgstr ""
 "Base de cerca per a l'objecte que conté informació sobre el domini de l'IPA"
 
-#: src/config/SSSDConfig/__init__.py.in:167
+#: src/config/SSSDConfig/__init__.py.in:172
 msgid "Search base for objects containing info about ID ranges"
 msgstr ""
 "Base de cerca per als objectes que contenen informació sobre els intervals "
 "d'id."
 
-#: src/config/SSSDConfig/__init__.py.in:168
-#: src/config/SSSDConfig/__init__.py.in:182
+#: src/config/SSSDConfig/__init__.py.in:173
+#: src/config/SSSDConfig/__init__.py.in:187
 msgid "Enable DNS sites - location based service discovery"
 msgstr ""
 "Habilita els llocs DNS - la localització es basa en el descobriment del "
 "servei"
 
-#: src/config/SSSDConfig/__init__.py.in:169
+#: src/config/SSSDConfig/__init__.py.in:174
 msgid "Search base for view containers"
 msgstr ""
 
-#: src/config/SSSDConfig/__init__.py.in:170
+#: src/config/SSSDConfig/__init__.py.in:175
 msgid "Objectclass for view containers"
 msgstr "Objectclass per veure els contenidors"
 
-#: src/config/SSSDConfig/__init__.py.in:171
+#: src/config/SSSDConfig/__init__.py.in:176
 msgid "Attribute with the name of the view"
 msgstr "Atribut amb el nom de la vista"
 
-#: src/config/SSSDConfig/__init__.py.in:172
+#: src/config/SSSDConfig/__init__.py.in:177
 msgid "Objectclass for override objects"
 msgstr ""
 
-#: src/config/SSSDConfig/__init__.py.in:173
+#: src/config/SSSDConfig/__init__.py.in:178
 msgid "Attribute with the reference to the original object"
 msgstr ""
 
-#: src/config/SSSDConfig/__init__.py.in:174
+#: src/config/SSSDConfig/__init__.py.in:179
 msgid "Objectclass for user override objects"
 msgstr ""
 
-#: src/config/SSSDConfig/__init__.py.in:175
+#: src/config/SSSDConfig/__init__.py.in:180
 msgid "Objectclass for group override objects"
 msgstr ""
 
-#: src/config/SSSDConfig/__init__.py.in:178
+#: src/config/SSSDConfig/__init__.py.in:183
 msgid "Active Directory domain"
 msgstr "Domini Active Directory"
 
-#: src/config/SSSDConfig/__init__.py.in:179
+#: src/config/SSSDConfig/__init__.py.in:184
 msgid "Active Directory server address"
 msgstr "Adreça del servidor de l'Active Directory"
 
-#: src/config/SSSDConfig/__init__.py.in:180
+#: src/config/SSSDConfig/__init__.py.in:185
 msgid "Active Directory backup server address"
 msgstr "Adreça del servidor de l'Active Directory de reserva"
 
-#: src/config/SSSDConfig/__init__.py.in:181
+#: src/config/SSSDConfig/__init__.py.in:186
 msgid "Active Directory client hostname"
 msgstr "Nom d'amfitrió del client d'Active Directory"
 
-#: src/config/SSSDConfig/__init__.py.in:183
-#: src/config/SSSDConfig/__init__.py.in:362
+#: src/config/SSSDConfig/__init__.py.in:188
+#: src/config/SSSDConfig/__init__.py.in:368
 msgid "LDAP filter to determine access privileges"
 msgstr "Filtre LDAP per determinar els privilegis d'accés"
 
-#: src/config/SSSDConfig/__init__.py.in:184
+#: src/config/SSSDConfig/__init__.py.in:189
 msgid "Whether to use the Global Catalog for lookups"
 msgstr ""
 
-#: src/config/SSSDConfig/__init__.py.in:185
+#: src/config/SSSDConfig/__init__.py.in:190
 msgid "Operation mode for GPO-based access control"
 msgstr "Mode d'operació per al control d'accés basat en GPO"
 
-#: src/config/SSSDConfig/__init__.py.in:186
+#: src/config/SSSDConfig/__init__.py.in:191
 msgid ""
 "The amount of time between lookups of the GPO policy files against the AD "
 "server"
 msgstr ""
 
-#: src/config/SSSDConfig/__init__.py.in:187
+#: src/config/SSSDConfig/__init__.py.in:192
 msgid ""
 "PAM service names that map to the GPO (Deny)InteractiveLogonRight policy "
 "settings"
 msgstr ""
 
-#: src/config/SSSDConfig/__init__.py.in:188
+#: src/config/SSSDConfig/__init__.py.in:193
 msgid ""
 "PAM service names that map to the GPO (Deny)RemoteInteractiveLogonRight "
 "policy settings"
 msgstr ""
 
-#: src/config/SSSDConfig/__init__.py.in:189
+#: src/config/SSSDConfig/__init__.py.in:194
 msgid ""
-"PAM service names that map to the GPO (Deny)NetworkLogonRight policy "
-"settings"
+"PAM service names that map to the GPO (Deny)NetworkLogonRight policy settings"
 msgstr ""
 
-#: src/config/SSSDConfig/__init__.py.in:190
+#: src/config/SSSDConfig/__init__.py.in:195
 msgid ""
 "PAM service names that map to the GPO (Deny)BatchLogonRight policy settings"
 msgstr ""
 
-#: src/config/SSSDConfig/__init__.py.in:191
+#: src/config/SSSDConfig/__init__.py.in:196
 msgid ""
-"PAM service names that map to the GPO (Deny)ServiceLogonRight policy "
-"settings"
+"PAM service names that map to the GPO (Deny)ServiceLogonRight policy settings"
 msgstr ""
 
-#: src/config/SSSDConfig/__init__.py.in:192
+#: src/config/SSSDConfig/__init__.py.in:197
 msgid "PAM service names for which GPO-based access is always granted"
 msgstr ""
 
-#: src/config/SSSDConfig/__init__.py.in:193
+#: src/config/SSSDConfig/__init__.py.in:198
 msgid "PAM service names for which GPO-based access is always denied"
 msgstr ""
 
-#: src/config/SSSDConfig/__init__.py.in:194
+#: src/config/SSSDConfig/__init__.py.in:199
 msgid ""
 "Default logon right (or permit/deny) to use for unmapped PAM service names"
 msgstr ""
 
-#: src/config/SSSDConfig/__init__.py.in:195
+#: src/config/SSSDConfig/__init__.py.in:200
 msgid "a particular site to be used by the client"
 msgstr ""
 
-#: src/config/SSSDConfig/__init__.py.in:198
-#: src/config/SSSDConfig/__init__.py.in:199
+#: src/config/SSSDConfig/__init__.py.in:203
+#: src/config/SSSDConfig/__init__.py.in:204
 msgid "Kerberos server address"
 msgstr "Adreça del servidor Kerberos"
 
-#: src/config/SSSDConfig/__init__.py.in:200
+#: src/config/SSSDConfig/__init__.py.in:205
 msgid "Kerberos backup server address"
 msgstr "Adreça de servidor  Kerberos de reserva"
 
-#: src/config/SSSDConfig/__init__.py.in:201
+#: src/config/SSSDConfig/__init__.py.in:206
 msgid "Kerberos realm"
 msgstr "Reialme Kerberos"
 
-#: src/config/SSSDConfig/__init__.py.in:202
+#: src/config/SSSDConfig/__init__.py.in:207
 msgid "Authentication timeout"
 msgstr "Temps d'expiració de l'autenticació"
 
-#: src/config/SSSDConfig/__init__.py.in:203
+#: src/config/SSSDConfig/__init__.py.in:208
 msgid "Whether to create kdcinfo files"
 msgstr "Si es creen els fitxers kdcinfo"
 
-#: src/config/SSSDConfig/__init__.py.in:204
+#: src/config/SSSDConfig/__init__.py.in:209
 msgid "Where to drop krb5 config snippets"
 msgstr ""
 
-#: src/config/SSSDConfig/__init__.py.in:207
+#: src/config/SSSDConfig/__init__.py.in:212
 msgid "Directory to store credential caches"
 msgstr "Directori per emmagatzemar la memòria auxiliar de les credencials"
 
-#: src/config/SSSDConfig/__init__.py.in:208
+#: src/config/SSSDConfig/__init__.py.in:213
 msgid "Location of the user's credential cache"
 msgstr "Ubicació de la memòria auxiliar de les credencials de l'usuari"
 
-#: src/config/SSSDConfig/__init__.py.in:209
+#: src/config/SSSDConfig/__init__.py.in:214
 msgid "Location of the keytab to validate credentials"
 msgstr "Ubicació de la clau per validar les credencials"
 
-#: src/config/SSSDConfig/__init__.py.in:210
+#: src/config/SSSDConfig/__init__.py.in:215
 msgid "Enable credential validation"
 msgstr "Activa la validació de credencials"
 
-#: src/config/SSSDConfig/__init__.py.in:211
+#: src/config/SSSDConfig/__init__.py.in:216
 msgid "Store password if offline for later online authentication"
 msgstr ""
 "Emmagatzema la contrasenya quan estigui fora de línia per autenticació en "
 "línia posterior"
 
-#: src/config/SSSDConfig/__init__.py.in:212
+#: src/config/SSSDConfig/__init__.py.in:217
 msgid "Renewable lifetime of the TGT"
 msgstr "Temps de vida renovable del TGT"
 
-#: src/config/SSSDConfig/__init__.py.in:213
+#: src/config/SSSDConfig/__init__.py.in:218
 msgid "Lifetime of the TGT"
 msgstr "Temps de vida del TGT"
 
-#: src/config/SSSDConfig/__init__.py.in:214
+#: src/config/SSSDConfig/__init__.py.in:219
 msgid "Time between two checks for renewal"
 msgstr "Temps entre les dues comprovacions per renovar"
 
-#: src/config/SSSDConfig/__init__.py.in:215
+#: src/config/SSSDConfig/__init__.py.in:220
 msgid "Enables FAST"
 msgstr "Activa FAST"
 
-#: src/config/SSSDConfig/__init__.py.in:216
+#: src/config/SSSDConfig/__init__.py.in:221
 msgid "Selects the principal to use for FAST"
 msgstr "Selecciona el principal per utilitzar amb FAST"
 
-#: src/config/SSSDConfig/__init__.py.in:217
+#: src/config/SSSDConfig/__init__.py.in:222
 msgid "Enables principal canonicalization"
 msgstr "Activa la canonització del principal"
 
-#: src/config/SSSDConfig/__init__.py.in:218
+#: src/config/SSSDConfig/__init__.py.in:223
 msgid "Enables enterprise principals"
 msgstr "Habilita els principals empresarials"
 
-#: src/config/SSSDConfig/__init__.py.in:219
+#: src/config/SSSDConfig/__init__.py.in:224
 msgid "A mapping from user names to kerberos principal names"
 msgstr ""
 
-#: src/config/SSSDConfig/__init__.py.in:222
-#: src/config/SSSDConfig/__init__.py.in:223
+#: src/config/SSSDConfig/__init__.py.in:227
+#: src/config/SSSDConfig/__init__.py.in:228
 msgid "Server where the change password service is running if not on the KDC"
-msgstr ""
-"Servidor on es troba el servei de canvi de contrasenya si no és al KDC"
+msgstr "Servidor on es troba el servei de canvi de contrasenya si no és al KDC"
 
-#: src/config/SSSDConfig/__init__.py.in:226
+#: src/config/SSSDConfig/__init__.py.in:231
 msgid "ldap_uri, The URI of the LDAP server"
 msgstr "ldap_uri, La URI del servidor LDAP"
 
-#: src/config/SSSDConfig/__init__.py.in:227
+#: src/config/SSSDConfig/__init__.py.in:232
 msgid "ldap_backup_uri, The URI of the LDAP server"
 msgstr "ldap_backup_uri, la URI del servidor LDAP"
 
-#: src/config/SSSDConfig/__init__.py.in:228
+#: src/config/SSSDConfig/__init__.py.in:233
 msgid "The default base DN"
 msgstr "La base DN per defecte"
 
-#: src/config/SSSDConfig/__init__.py.in:229
+#: src/config/SSSDConfig/__init__.py.in:234
 msgid "The Schema Type in use on the LDAP server, rfc2307"
 msgstr "El tipus d'esquema en ús al servidor LDAP, rfc2307"
 
-#: src/config/SSSDConfig/__init__.py.in:230
+#: src/config/SSSDConfig/__init__.py.in:235
 msgid "The default bind DN"
 msgstr "DN de creació del vincle per defecte"
 
-#: src/config/SSSDConfig/__init__.py.in:231
+#: src/config/SSSDConfig/__init__.py.in:236
 msgid "The type of the authentication token of the default bind DN"
 msgstr ""
 "El tipus del testimoni d'autenticació del DN de creació del vincle per "
 "defecte"
 
-#: src/config/SSSDConfig/__init__.py.in:232
+#: src/config/SSSDConfig/__init__.py.in:237
 msgid "The authentication token of the default bind DN"
 msgstr "El testimoni d'autenticació del DN de creació del vincle per defecte"
 
-#: src/config/SSSDConfig/__init__.py.in:233
+#: src/config/SSSDConfig/__init__.py.in:238
 msgid "Length of time to attempt connection"
 msgstr "Llargària del temps per intentar una connexió"
 
-#: src/config/SSSDConfig/__init__.py.in:234
+#: src/config/SSSDConfig/__init__.py.in:239
 msgid "Length of time to attempt synchronous LDAP operations"
 msgstr "Llargària del temps per intentar operacions LDAP asíncrones"
 
-#: src/config/SSSDConfig/__init__.py.in:235
+#: src/config/SSSDConfig/__init__.py.in:240
 msgid "Length of time between attempts to reconnect while offline"
 msgstr ""
-"Llargària del temps entre intents per re-connectar quan estigui fora de "
-"línia"
+"Llargària del temps entre intents per re-connectar quan estigui fora de línia"
 
-#: src/config/SSSDConfig/__init__.py.in:236
+#: src/config/SSSDConfig/__init__.py.in:241
 msgid "Use only the upper case for realm names"
 msgstr "Utilitza només majúscules pels noms de reialme"
 
-#: src/config/SSSDConfig/__init__.py.in:237
+#: src/config/SSSDConfig/__init__.py.in:242
 msgid "File that contains CA certificates"
 msgstr "Fitxer que conté els certificats CA"
 
-#: src/config/SSSDConfig/__init__.py.in:238
+#: src/config/SSSDConfig/__init__.py.in:243
 msgid "Path to CA certificate directory"
 msgstr "Camí al directori del certificat de l'AC"
 
-#: src/config/SSSDConfig/__init__.py.in:239
+#: src/config/SSSDConfig/__init__.py.in:244
 msgid "File that contains the client certificate"
 msgstr "Fitxer que conté el certificat de client"
 
-#: src/config/SSSDConfig/__init__.py.in:240
+#: src/config/SSSDConfig/__init__.py.in:245
 msgid "File that contains the client key"
 msgstr "Fitxer que conté la clau de client"
 
-#: src/config/SSSDConfig/__init__.py.in:241
+#: src/config/SSSDConfig/__init__.py.in:246
 msgid "List of possible ciphers suites"
 msgstr "Llista de paquets de xifrat possibles"
 
-#: src/config/SSSDConfig/__init__.py.in:242
+#: src/config/SSSDConfig/__init__.py.in:247
 msgid "Require TLS certificate verification"
 msgstr "Requereix verificació de certificat TLS"
 
-#: src/config/SSSDConfig/__init__.py.in:243
+#: src/config/SSSDConfig/__init__.py.in:248
 msgid "Specify the sasl mechanism to use"
 msgstr "Especifica el mecanisme SASL a utilitzar"
 
-#: src/config/SSSDConfig/__init__.py.in:244
+#: src/config/SSSDConfig/__init__.py.in:249
 msgid "Specify the sasl authorization id to use"
 msgstr "Especifica l'id. d'autorització SASL a utilitzar"
 
-#: src/config/SSSDConfig/__init__.py.in:245
+#: src/config/SSSDConfig/__init__.py.in:250
 msgid "Specify the sasl authorization realm to use"
 msgstr "Especifica el reialme d'autorització SASL a utilitzar"
 
-#: src/config/SSSDConfig/__init__.py.in:246
+#: src/config/SSSDConfig/__init__.py.in:251
 msgid "Specify the minimal SSF for LDAP sasl authorization"
 msgstr "Especifica el SSF mínim per autorització SASL de LDAP"
 
-#: src/config/SSSDConfig/__init__.py.in:247
+#: src/config/SSSDConfig/__init__.py.in:252
 msgid "Kerberos service keytab"
 msgstr "Clau de servei Kerberos"
 
-#: src/config/SSSDConfig/__init__.py.in:248
+#: src/config/SSSDConfig/__init__.py.in:253
 msgid "Use Kerberos auth for LDAP connection"
 msgstr "Utilitza autenticació Kerberos per la connexió LDAP"
 
-#: src/config/SSSDConfig/__init__.py.in:249
+#: src/config/SSSDConfig/__init__.py.in:254
 msgid "Follow LDAP referrals"
 msgstr "Segueix les referències LDAP"
 
-#: src/config/SSSDConfig/__init__.py.in:250
+#: src/config/SSSDConfig/__init__.py.in:255
 msgid "Lifetime of TGT for LDAP connection"
 msgstr "Temps de vida del TGT per la connexió LDAP"
 
-#: src/config/SSSDConfig/__init__.py.in:251
+#: src/config/SSSDConfig/__init__.py.in:256
 msgid "How to dereference aliases"
 msgstr "Com desreferenciar àlies"
 
-#: src/config/SSSDConfig/__init__.py.in:252
+#: src/config/SSSDConfig/__init__.py.in:257
 msgid "Service name for DNS service lookups"
 msgstr "Nom del servei per la recerca del servei del DNS"
 
-#: src/config/SSSDConfig/__init__.py.in:253
+#: src/config/SSSDConfig/__init__.py.in:258
 msgid "The number of records to retrieve in a single LDAP query"
 msgstr "El número de registres a recuperar en una sola petició LDAP"
 
-#: src/config/SSSDConfig/__init__.py.in:254
+#: src/config/SSSDConfig/__init__.py.in:259
 msgid "The number of members that must be missing to trigger a full deref"
 msgstr ""
-"El número de membres que han de faltar per activar una de-referència "
-"completa"
+"El número de membres que han de faltar per activar una de-referència completa"
 
-#: src/config/SSSDConfig/__init__.py.in:255
+#: src/config/SSSDConfig/__init__.py.in:260
 msgid ""
 "Whether the LDAP library should perform a reverse lookup to canonicalize the "
 "host name during a SASL bind"
@@ -823,371 +839,374 @@ msgstr ""
 "Si la biblioteca LDAP hauria de realitzar una recerca inversa per "
 "canonalitzar el nom d'amfitrió durant la creació del vincle SASL"
 
-#: src/config/SSSDConfig/__init__.py.in:257
+#: src/config/SSSDConfig/__init__.py.in:262
 msgid "entryUSN attribute"
 msgstr "Atribut entryUSN"
 
-#: src/config/SSSDConfig/__init__.py.in:258
+#: src/config/SSSDConfig/__init__.py.in:263
 msgid "lastUSN attribute"
 msgstr "Atribut lastUSN"
 
-#: src/config/SSSDConfig/__init__.py.in:260
-msgid ""
-"How long to retain a connection to the LDAP server before disconnecting"
+#: src/config/SSSDConfig/__init__.py.in:265
+msgid "How long to retain a connection to the LDAP server before disconnecting"
 msgstr ""
 "Quant temps s'ha de retenir una connexió al servidor LDAP abans de "
 "desconnectar"
 
-#: src/config/SSSDConfig/__init__.py.in:262
+#: src/config/SSSDConfig/__init__.py.in:267
 msgid "Disable the LDAP paging control"
 msgstr "Desactiva el control de paginació LDAP"
 
-#: src/config/SSSDConfig/__init__.py.in:263
+#: src/config/SSSDConfig/__init__.py.in:268
 msgid "Disable Active Directory range retrieval"
 msgstr "Inhabilita la recuperació de l'interval de l'Active Directory"
 
-#: src/config/SSSDConfig/__init__.py.in:266
+#: src/config/SSSDConfig/__init__.py.in:271
 msgid "Length of time to wait for a search request"
 msgstr "Llargària de temps a esperar per una petició de cerca"
 
-#: src/config/SSSDConfig/__init__.py.in:267
+#: src/config/SSSDConfig/__init__.py.in:272
 msgid "Length of time to wait for a enumeration request"
 msgstr "Llargària de temps a esperar per una petició d'enumeració"
 
-#: src/config/SSSDConfig/__init__.py.in:268
+#: src/config/SSSDConfig/__init__.py.in:273
 msgid "Length of time between enumeration updates"
 msgstr "Llargària de temps entre actualitzacions d'enumeració"
 
-#: src/config/SSSDConfig/__init__.py.in:269
+#: src/config/SSSDConfig/__init__.py.in:274
 msgid "Length of time between cache cleanups"
 msgstr "Longevitat entre les neteges de la memòria auxiliar"
 
-#: src/config/SSSDConfig/__init__.py.in:270
+#: src/config/SSSDConfig/__init__.py.in:275
 msgid "Require TLS for ID lookups"
 msgstr "Requereix TLS per a la recerca d'id."
 
-#: src/config/SSSDConfig/__init__.py.in:271
+#: src/config/SSSDConfig/__init__.py.in:276
 msgid "Use ID-mapping of objectSID instead of pre-set IDs"
 msgstr ""
 "Utilitza l'assignació d'id. de l'objectSID enlloc dels id. pre-establerts"
 
-#: src/config/SSSDConfig/__init__.py.in:272
+#: src/config/SSSDConfig/__init__.py.in:277
 msgid "Base DN for user lookups"
 msgstr "DN base per a la recerca de l'usuari"
 
-#: src/config/SSSDConfig/__init__.py.in:273
+#: src/config/SSSDConfig/__init__.py.in:278
 msgid "Scope of user lookups"
 msgstr "Abast de la recerca de l'usuari"
 
-#: src/config/SSSDConfig/__init__.py.in:274
+#: src/config/SSSDConfig/__init__.py.in:279
 msgid "Filter for user lookups"
 msgstr "Filtre per a la recerca de l'usuari"
 
-#: src/config/SSSDConfig/__init__.py.in:275
+#: src/config/SSSDConfig/__init__.py.in:280
 msgid "Objectclass for users"
 msgstr "Objectclass dels usuaris"
 
-#: src/config/SSSDConfig/__init__.py.in:276
+#: src/config/SSSDConfig/__init__.py.in:281
 msgid "Username attribute"
 msgstr "Atribut del nom d'usuari"
 
-#: src/config/SSSDConfig/__init__.py.in:278
+#: src/config/SSSDConfig/__init__.py.in:283
 msgid "UID attribute"
 msgstr "Atribut de l'UID"
 
-#: src/config/SSSDConfig/__init__.py.in:279
+#: src/config/SSSDConfig/__init__.py.in:284
 msgid "Primary GID attribute"
 msgstr "Atribut del GID primari"
 
-#: src/config/SSSDConfig/__init__.py.in:280
+#: src/config/SSSDConfig/__init__.py.in:285
 msgid "GECOS attribute"
 msgstr "Atribut del GECOS"
 
-#: src/config/SSSDConfig/__init__.py.in:281
+#: src/config/SSSDConfig/__init__.py.in:286
 msgid "Home directory attribute"
 msgstr "Atribut del directori d'usuari"
 
-#: src/config/SSSDConfig/__init__.py.in:282
+#: src/config/SSSDConfig/__init__.py.in:287
 msgid "Shell attribute"
 msgstr "Atribut del shell"
 
-#: src/config/SSSDConfig/__init__.py.in:283
+#: src/config/SSSDConfig/__init__.py.in:288
 msgid "UUID attribute"
 msgstr "Atribut del UUID"
 
-#: src/config/SSSDConfig/__init__.py.in:284
-#: src/config/SSSDConfig/__init__.py.in:324
+#: src/config/SSSDConfig/__init__.py.in:289
+#: src/config/SSSDConfig/__init__.py.in:329
 msgid "objectSID attribute"
 msgstr "Atribut de l'objectSID"
 
-#: src/config/SSSDConfig/__init__.py.in:285
+#: src/config/SSSDConfig/__init__.py.in:290
 msgid "Active Directory primary group attribute for ID-mapping"
 msgstr ""
 "Atribut del grup primari de l'Active Directory per a l'assignació d'id."
 
-#: src/config/SSSDConfig/__init__.py.in:286
+#: src/config/SSSDConfig/__init__.py.in:291
 msgid "User principal attribute (for Kerberos)"
 msgstr "Atribut d'usuari principal (per a Kerberos)"
 
-#: src/config/SSSDConfig/__init__.py.in:287
+#: src/config/SSSDConfig/__init__.py.in:292
 msgid "Full Name"
 msgstr "Nom complet"
 
-#: src/config/SSSDConfig/__init__.py.in:288
+#: src/config/SSSDConfig/__init__.py.in:293
 msgid "memberOf attribute"
 msgstr "Atribut memberOf"
 
-#: src/config/SSSDConfig/__init__.py.in:289
+#: src/config/SSSDConfig/__init__.py.in:294
 msgid "Modification time attribute"
 msgstr "Atribut de la data de modificació"
 
-#: src/config/SSSDConfig/__init__.py.in:291
+#: src/config/SSSDConfig/__init__.py.in:296
 msgid "shadowLastChange attribute"
 msgstr "Atribut shadowLastChange"
 
-#: src/config/SSSDConfig/__init__.py.in:292
+#: src/config/SSSDConfig/__init__.py.in:297
 msgid "shadowMin attribute"
 msgstr "Atribut shadowMin"
 
-#: src/config/SSSDConfig/__init__.py.in:293
+#: src/config/SSSDConfig/__init__.py.in:298
 msgid "shadowMax attribute"
 msgstr "Atribut shadowMax"
 
-#: src/config/SSSDConfig/__init__.py.in:294
+#: src/config/SSSDConfig/__init__.py.in:299
 msgid "shadowWarning attribute"
 msgstr "Atribut shadowWarning"
 
-#: src/config/SSSDConfig/__init__.py.in:295
+#: src/config/SSSDConfig/__init__.py.in:300
 msgid "shadowInactive attribute"
 msgstr "Atribut shadowInactive"
 
-#: src/config/SSSDConfig/__init__.py.in:296
+#: src/config/SSSDConfig/__init__.py.in:301
 msgid "shadowExpire attribute"
 msgstr "Atribut shadowExpire"
 
-#: src/config/SSSDConfig/__init__.py.in:297
+#: src/config/SSSDConfig/__init__.py.in:302
 msgid "shadowFlag attribute"
 msgstr "Atribut shadowFlag"
 
-#: src/config/SSSDConfig/__init__.py.in:298
+#: src/config/SSSDConfig/__init__.py.in:303
 msgid "Attribute listing authorized PAM services"
 msgstr "Atribut que llista els serveis PAM autoritzats"
 
-#: src/config/SSSDConfig/__init__.py.in:299
+#: src/config/SSSDConfig/__init__.py.in:304
 msgid "Attribute listing authorized server hosts"
 msgstr "Llista els atributs dels amfitrions dels servidors autoritzats"
 
-#: src/config/SSSDConfig/__init__.py.in:300
+#: src/config/SSSDConfig/__init__.py.in:305
 msgid "krbLastPwdChange attribute"
 msgstr "Atribut krbLastPwdChange"
 
-#: src/config/SSSDConfig/__init__.py.in:301
+#: src/config/SSSDConfig/__init__.py.in:306
 msgid "krbPasswordExpiration attribute"
 msgstr "Atribut krbPasswordExpiration"
 
-#: src/config/SSSDConfig/__init__.py.in:302
+#: src/config/SSSDConfig/__init__.py.in:307
 msgid "Attribute indicating that server side password policies are active"
 msgstr ""
 "Atribut que indica l'activació de les polítiques de contrasenya de servidor"
 
-#: src/config/SSSDConfig/__init__.py.in:303
+#: src/config/SSSDConfig/__init__.py.in:308
 msgid "accountExpires attribute of AD"
 msgstr "Atribut accountExpires de l'AD"
 
-#: src/config/SSSDConfig/__init__.py.in:304
+#: src/config/SSSDConfig/__init__.py.in:309
 msgid "userAccountControl attribute of AD"
 msgstr "Atribut userAccountControl de l'AD"
 
-#: src/config/SSSDConfig/__init__.py.in:305
+#: src/config/SSSDConfig/__init__.py.in:310
 msgid "nsAccountLock attribute"
 msgstr "Atribut nsAccountLock"
 
-#: src/config/SSSDConfig/__init__.py.in:306
+#: src/config/SSSDConfig/__init__.py.in:311
 msgid "loginDisabled attribute of NDS"
 msgstr "Atribut loginDisabled del NDS"
 
-#: src/config/SSSDConfig/__init__.py.in:307
+#: src/config/SSSDConfig/__init__.py.in:312
 msgid "loginExpirationTime attribute of NDS"
 msgstr "Atribut del NDS de loginExpirationTime"
 
-#: src/config/SSSDConfig/__init__.py.in:308
+#: src/config/SSSDConfig/__init__.py.in:313
 msgid "loginAllowedTimeMap attribute of NDS"
 msgstr "Atribut loginAllowedTimeMap del NDS"
 
-#: src/config/SSSDConfig/__init__.py.in:309
+#: src/config/SSSDConfig/__init__.py.in:314
 msgid "SSH public key attribute"
 msgstr "Atribut de la clau pública SSH"
 
-#: src/config/SSSDConfig/__init__.py.in:310
+#: src/config/SSSDConfig/__init__.py.in:315
 msgid "attribute listing allowed authentication types for a user"
 msgstr ""
 
-#: src/config/SSSDConfig/__init__.py.in:311
+#: src/config/SSSDConfig/__init__.py.in:316
 msgid "attribute containing the X509 certificate of the user"
 msgstr ""
 
-#: src/config/SSSDConfig/__init__.py.in:313
+#: src/config/SSSDConfig/__init__.py.in:318
 msgid "A list of extra attributes to download along with the user entry"
 msgstr ""
 
-#: src/config/SSSDConfig/__init__.py.in:315
+#: src/config/SSSDConfig/__init__.py.in:320
 msgid "Base DN for group lookups"
 msgstr "DN base per a la recerca del grup"
 
-#: src/config/SSSDConfig/__init__.py.in:318
+#: src/config/SSSDConfig/__init__.py.in:323
 msgid "Objectclass for groups"
 msgstr "Objectclass per grups"
 
-#: src/config/SSSDConfig/__init__.py.in:319
+#: src/config/SSSDConfig/__init__.py.in:324
 msgid "Group name"
 msgstr "Nom del grup"
 
-#: src/config/SSSDConfig/__init__.py.in:320
+#: src/config/SSSDConfig/__init__.py.in:325
 msgid "Group password"
 msgstr "Contrasenya del grup"
 
-#: src/config/SSSDConfig/__init__.py.in:321
+#: src/config/SSSDConfig/__init__.py.in:326
 msgid "GID attribute"
 msgstr "Atribut GID"
 
-#: src/config/SSSDConfig/__init__.py.in:322
+#: src/config/SSSDConfig/__init__.py.in:327
 msgid "Group member attribute"
 msgstr "Atribut de membre del grup"
 
-#: src/config/SSSDConfig/__init__.py.in:323
+#: src/config/SSSDConfig/__init__.py.in:328
 msgid "Group UUID attribute"
 msgstr "Atribut UUID del grup"
 
-#: src/config/SSSDConfig/__init__.py.in:325
+#: src/config/SSSDConfig/__init__.py.in:330
 msgid "Modification time attribute for groups"
 msgstr "Atribut de data de modificació per als grups"
 
-#: src/config/SSSDConfig/__init__.py.in:326
+#: src/config/SSSDConfig/__init__.py.in:331
 msgid "Type of the group and other flags"
 msgstr ""
 
-#: src/config/SSSDConfig/__init__.py.in:328
+#: src/config/SSSDConfig/__init__.py.in:333
 msgid "Maximum nesting level SSSd will follow"
 msgstr "Nivell màxim d'encadenament que seguirà l'SSSd"
 
-#: src/config/SSSDConfig/__init__.py.in:330
+#: src/config/SSSDConfig/__init__.py.in:335
 msgid "Base DN for netgroup lookups"
 msgstr "DN base per a la recerca del grups de xarxa"
 
-#: src/config/SSSDConfig/__init__.py.in:331
+#: src/config/SSSDConfig/__init__.py.in:336
 msgid "Objectclass for netgroups"
 msgstr "Objectclass per grups de xarxa"
 
-#: src/config/SSSDConfig/__init__.py.in:332
+#: src/config/SSSDConfig/__init__.py.in:337
 msgid "Netgroup name"
 msgstr "Nom de grup de xarxa"
 
-#: src/config/SSSDConfig/__init__.py.in:333
+#: src/config/SSSDConfig/__init__.py.in:338
 msgid "Netgroups members attribute"
 msgstr "Atribut dels membres del grup de xarxa"
 
-#: src/config/SSSDConfig/__init__.py.in:334
+#: src/config/SSSDConfig/__init__.py.in:339
 msgid "Netgroup triple attribute"
 msgstr "Atribut triple del grup de xarxa"
 
-#: src/config/SSSDConfig/__init__.py.in:335
+#: src/config/SSSDConfig/__init__.py.in:340
 msgid "Modification time attribute for netgroups"
 msgstr "Atribut de data de modificació per als grups de xarxa"
 
-#: src/config/SSSDConfig/__init__.py.in:337
+#: src/config/SSSDConfig/__init__.py.in:342
 msgid "Base DN for service lookups"
 msgstr "DN base per a la recerca del servei"
 
-#: src/config/SSSDConfig/__init__.py.in:338
+#: src/config/SSSDConfig/__init__.py.in:343
 msgid "Objectclass for services"
 msgstr "Objectclass per serveis"
 
-#: src/config/SSSDConfig/__init__.py.in:339
+#: src/config/SSSDConfig/__init__.py.in:344
 msgid "Service name attribute"
 msgstr "Atribut del nom del servei"
 
-#: src/config/SSSDConfig/__init__.py.in:340
+#: src/config/SSSDConfig/__init__.py.in:345
 msgid "Service port attribute"
 msgstr "Atribut del port del servei"
 
-#: src/config/SSSDConfig/__init__.py.in:341
+#: src/config/SSSDConfig/__init__.py.in:346
 msgid "Service protocol attribute"
 msgstr "Atribut del protocol del servei"
 
-#: src/config/SSSDConfig/__init__.py.in:344
+#: src/config/SSSDConfig/__init__.py.in:349
 msgid "Lower bound for ID-mapping"
 msgstr "Límit inferior per a l'assignació d'id."
 
-#: src/config/SSSDConfig/__init__.py.in:345
+#: src/config/SSSDConfig/__init__.py.in:350
 msgid "Upper bound for ID-mapping"
 msgstr "Límit superior per a l'assignació d'id."
 
-#: src/config/SSSDConfig/__init__.py.in:346
+#: src/config/SSSDConfig/__init__.py.in:351
 msgid "Number of IDs for each slice when ID-mapping"
 msgstr "Nombres d'id. per cada porció en l'assignació d'id."
 
-#: src/config/SSSDConfig/__init__.py.in:347
+#: src/config/SSSDConfig/__init__.py.in:352
 msgid "Use autorid-compatible algorithm for ID-mapping"
 msgstr "Utilitza l'algoritme compatible d'autorid per a l'assignació d'id."
 
-#: src/config/SSSDConfig/__init__.py.in:348
+#: src/config/SSSDConfig/__init__.py.in:353
 msgid "Name of the default domain for ID-mapping"
 msgstr "Nom del domini per defecte per a l'assignació d'id."
 
-#: src/config/SSSDConfig/__init__.py.in:349
+#: src/config/SSSDConfig/__init__.py.in:354
 msgid "SID of the default domain for ID-mapping"
 msgstr "SID del domini per defecte per a l'assignació d'id."
 
-#: src/config/SSSDConfig/__init__.py.in:351
+#: src/config/SSSDConfig/__init__.py.in:356
 msgid "Use LDAP_MATCHING_RULE_IN_CHAIN for group lookups"
 msgstr "Utilitza LDAP_MATCHING_RULE_IN_CHAIN per a la recerca del grup"
 
-#: src/config/SSSDConfig/__init__.py.in:352
+#: src/config/SSSDConfig/__init__.py.in:357
 msgid "Use LDAP_MATCHING_RULE_IN_CHAIN for initgroup lookups"
 msgstr "Utilitza LDAP_MATCHING_RULE_IN_CHAIN per a la recerca de l'initgroup"
 
-#: src/config/SSSDConfig/__init__.py.in:353
+#: src/config/SSSDConfig/__init__.py.in:358
 msgid "Whether to use Token-Groups"
 msgstr ""
 
-#: src/config/SSSDConfig/__init__.py.in:354
+#: src/config/SSSDConfig/__init__.py.in:359
 msgid "Set lower boundary for allowed IDs from the LDAP server"
 msgstr ""
 
-#: src/config/SSSDConfig/__init__.py.in:355
+#: src/config/SSSDConfig/__init__.py.in:360
 msgid "Set upper boundary for allowed IDs from the LDAP server"
 msgstr ""
 
-#: src/config/SSSDConfig/__init__.py.in:356
+#: src/config/SSSDConfig/__init__.py.in:361
 msgid "DN for ppolicy queries"
 msgstr "DN per a les consultes ppolicy"
 
-#: src/config/SSSDConfig/__init__.py.in:359
+#: src/config/SSSDConfig/__init__.py.in:362
+msgid "How many maximum entries to fetch during a wildcard request"
+msgstr ""
+
+#: src/config/SSSDConfig/__init__.py.in:365
 msgid "Policy to evaluate the password expiration"
 msgstr "Política per avaluar l'expiració de contrasenya"
 
-#: src/config/SSSDConfig/__init__.py.in:363
+#: src/config/SSSDConfig/__init__.py.in:369
 msgid "Which attributes shall be used to evaluate if an account is expired"
 msgstr ""
 "Quins atributs s'haurien d'utilitzar per avaluar si el compte ha vençut"
 
-#: src/config/SSSDConfig/__init__.py.in:364
+#: src/config/SSSDConfig/__init__.py.in:370
 msgid "Which rules should be used to evaluate access control"
 msgstr "Quines regles s'haurien d'utilitzar per avaluar el control d'accés"
 
-#: src/config/SSSDConfig/__init__.py.in:367
+#: src/config/SSSDConfig/__init__.py.in:373
 msgid "URI of an LDAP server where password changes are allowed"
 msgstr "L'URI d'un servidor LDAP on es permeten els canvis de contrasenya"
 
-#: src/config/SSSDConfig/__init__.py.in:368
+#: src/config/SSSDConfig/__init__.py.in:374
 msgid "URI of a backup LDAP server where password changes are allowed"
 msgstr "URI d'un servidor LDAP reserva on es permet canvis de contrasenya"
 
-#: src/config/SSSDConfig/__init__.py.in:369
+#: src/config/SSSDConfig/__init__.py.in:375
 msgid "DNS service name for LDAP password change server"
 msgstr "Nom del servei DNS pel servidor LDAP de canvi de contrasenyes"
 
-#: src/config/SSSDConfig/__init__.py.in:370
+#: src/config/SSSDConfig/__init__.py.in:376
 msgid ""
 "Whether to update the ldap_user_shadow_last_change attribute after a "
 "password change"
@@ -1195,23 +1214,23 @@ msgstr ""
 "Si s'actualitza l'atribut ldap_user_shadow_last_change després d'un canvi de "
 "contrasenya"
 
-#: src/config/SSSDConfig/__init__.py.in:373
+#: src/config/SSSDConfig/__init__.py.in:379
 msgid "Base DN for sudo rules lookups"
 msgstr "DN base per a la recerca de les regles sudo"
 
-#: src/config/SSSDConfig/__init__.py.in:374
+#: src/config/SSSDConfig/__init__.py.in:380
 msgid "Automatic full refresh period"
 msgstr "Període d'actualització automàtica completa"
 
-#: src/config/SSSDConfig/__init__.py.in:375
+#: src/config/SSSDConfig/__init__.py.in:381
 msgid "Automatic smart refresh period"
 msgstr "Període d'actualització automàtica intel·ligent"
 
-#: src/config/SSSDConfig/__init__.py.in:376
+#: src/config/SSSDConfig/__init__.py.in:382
 msgid "Whether to filter rules by hostname, IP addresses and network"
 msgstr "Si es filtren les regles per nom d'amfitrió, adreça IP i xarxa"
 
-#: src/config/SSSDConfig/__init__.py.in:377
+#: src/config/SSSDConfig/__init__.py.in:383
 msgid ""
 "Hostnames and/or fully qualified domain names of this machine to filter sudo "
 "rules"
@@ -1219,174 +1238,174 @@ msgstr ""
 "Noms d'amfitrió i/o noms de domini plenament qualificat d'aquesta màquina "
 "per filtrar les regles de sudo"
 
-#: src/config/SSSDConfig/__init__.py.in:378
+#: src/config/SSSDConfig/__init__.py.in:384
 msgid "IPv4 or IPv6 addresses or network of this machine to filter sudo rules"
 msgstr ""
 "Adreces IPv4 o IPv6 o xarxa d'aquesta màquina per filtrar regles de sudo"
 
-#: src/config/SSSDConfig/__init__.py.in:379
+#: src/config/SSSDConfig/__init__.py.in:385
 msgid "Whether to include rules that contains netgroup in host attribute"
 msgstr ""
 "Si s'inclouen les regles que contenen el netgroup a l'atribut de l'amfitrió"
 
-#: src/config/SSSDConfig/__init__.py.in:380
+#: src/config/SSSDConfig/__init__.py.in:386
 msgid ""
 "Whether to include rules that contains regular expression in host attribute"
 msgstr ""
 "Si s'inclouen les regles que contenen expressions regulars a l'atribut de "
 "l'amfitrió"
 
-#: src/config/SSSDConfig/__init__.py.in:381
+#: src/config/SSSDConfig/__init__.py.in:387
 msgid "Object class for sudo rules"
 msgstr "Objectclass de les regles sudo"
 
-#: src/config/SSSDConfig/__init__.py.in:382
+#: src/config/SSSDConfig/__init__.py.in:388
 msgid "Sudo rule name"
 msgstr "Nom de la regla sudo"
 
-#: src/config/SSSDConfig/__init__.py.in:383
+#: src/config/SSSDConfig/__init__.py.in:389
 msgid "Sudo rule command attribute"
 msgstr "Attribut command de la regla sudo"
 
-#: src/config/SSSDConfig/__init__.py.in:384
+#: src/config/SSSDConfig/__init__.py.in:390
 msgid "Sudo rule host attribute"
 msgstr "Atribut host de la regla sudo"
 
-#: src/config/SSSDConfig/__init__.py.in:385
+#: src/config/SSSDConfig/__init__.py.in:391
 msgid "Sudo rule user attribute"
 msgstr "Atribut user de la regla sudo"
 
-#: src/config/SSSDConfig/__init__.py.in:386
+#: src/config/SSSDConfig/__init__.py.in:392
 msgid "Sudo rule option attribute"
 msgstr "Atribut option de la regla sudo"
 
-#: src/config/SSSDConfig/__init__.py.in:387
+#: src/config/SSSDConfig/__init__.py.in:393
 msgid "Sudo rule runas attribute"
 msgstr "Atribut runas de la regla sudo"
 
-#: src/config/SSSDConfig/__init__.py.in:388
+#: src/config/SSSDConfig/__init__.py.in:394
 msgid "Sudo rule runasuser attribute"
 msgstr "Atribut runasuser de la regla sudo"
 
-#: src/config/SSSDConfig/__init__.py.in:389
+#: src/config/SSSDConfig/__init__.py.in:395
 msgid "Sudo rule runasgroup attribute"
 msgstr "Atribut runasgroup de la regla sudo"
 
-#: src/config/SSSDConfig/__init__.py.in:390
+#: src/config/SSSDConfig/__init__.py.in:396
 msgid "Sudo rule notbefore attribute"
 msgstr "Atribut notbefore de la regla sudo"
 
-#: src/config/SSSDConfig/__init__.py.in:391
+#: src/config/SSSDConfig/__init__.py.in:397
 msgid "Sudo rule notafter attribute"
 msgstr "Atribut notafter de la regla sudo"
 
-#: src/config/SSSDConfig/__init__.py.in:392
+#: src/config/SSSDConfig/__init__.py.in:398
 msgid "Sudo rule order attribute"
 msgstr "Atribut order de la regla sudo"
 
-#: src/config/SSSDConfig/__init__.py.in:395
+#: src/config/SSSDConfig/__init__.py.in:401
 msgid "Object class for automounter maps"
 msgstr "Objectclass per a l'assignació automounter"
 
-#: src/config/SSSDConfig/__init__.py.in:396
+#: src/config/SSSDConfig/__init__.py.in:402
 msgid "Automounter map name attribute"
 msgstr "Atribut del nom de l'assignació automounter"
 
-#: src/config/SSSDConfig/__init__.py.in:397
+#: src/config/SSSDConfig/__init__.py.in:403
 msgid "Object class for automounter map entries"
 msgstr "Objectclass de les entrades de l'assignació automounter"
 
-#: src/config/SSSDConfig/__init__.py.in:398
+#: src/config/SSSDConfig/__init__.py.in:404
 msgid "Automounter map entry key attribute"
 msgstr "Atribut de la clau d'entrada de l'assignació automounter"
 
-#: src/config/SSSDConfig/__init__.py.in:399
+#: src/config/SSSDConfig/__init__.py.in:405
 msgid "Automounter map entry value attribute"
 msgstr "Atribut del valor de l'entrada de l'assignació automounter"
 
-#: src/config/SSSDConfig/__init__.py.in:400
+#: src/config/SSSDConfig/__init__.py.in:406
 msgid "Base DN for automounter map lookups"
 msgstr "DN base per a la recerca de l'assignació automounter"
 
-#: src/config/SSSDConfig/__init__.py.in:403
+#: src/config/SSSDConfig/__init__.py.in:409
 msgid "Comma separated list of allowed users"
 msgstr "Llista separada per comes dels usuaris autoritzats"
 
-#: src/config/SSSDConfig/__init__.py.in:404
+#: src/config/SSSDConfig/__init__.py.in:410
 msgid "Comma separated list of prohibited users"
 msgstr "Llista separada per comes dels usuaris no autoritzats"
 
-#: src/config/SSSDConfig/__init__.py.in:407
+#: src/config/SSSDConfig/__init__.py.in:413
 msgid "Default shell, /bin/bash"
 msgstr "El shell predeterminat, /bin/bash"
 
-#: src/config/SSSDConfig/__init__.py.in:408
+#: src/config/SSSDConfig/__init__.py.in:414
 msgid "Base for home directories"
 msgstr "Base pels directoris d'usuari"
 
-#: src/config/SSSDConfig/__init__.py.in:411
+#: src/config/SSSDConfig/__init__.py.in:417
 msgid "The name of the NSS library to use"
 msgstr "El nom de la biblioteca NSS a utilitzar"
 
-#: src/config/SSSDConfig/__init__.py.in:412
+#: src/config/SSSDConfig/__init__.py.in:418
 msgid "Whether to look up canonical group name from cache if possible"
 msgstr ""
 "Si se cerca el nom del grup canònic des de la memòria auxiliar, si és "
 "possible"
 
-#: src/config/SSSDConfig/__init__.py.in:415
+#: src/config/SSSDConfig/__init__.py.in:421
 msgid "PAM stack to use"
 msgstr "Pila PAM a utilitzar"
 
-#: src/monitor/monitor.c:2838
+#: src/monitor/monitor.c:2872
 msgid "Become a daemon (default)"
 msgstr "Esdevé un dimoni (per defecte)"
 
-#: src/monitor/monitor.c:2840
+#: src/monitor/monitor.c:2874
 msgid "Run interactive (not a daemon)"
 msgstr "Executa en mode interactiu (no com a dimoni)"
 
-#: src/monitor/monitor.c:2842 src/tools/sss_debuglevel.c:71
+#: src/monitor/monitor.c:2876 src/tools/sss_debuglevel.c:71
 msgid "Specify a non-default config file"
 msgstr "Especifica un fitxer de configuració diferent al per defecte"
 
-#: src/monitor/monitor.c:2844
+#: src/monitor/monitor.c:2878
 msgid "Print version number and exit"
 msgstr "Imprimeix el número de versió i surt"
 
-#: src/providers/krb5/krb5_child.c:2592 src/providers/ldap/ldap_child.c:609
-#: src/util/util.h:110
+#: src/providers/krb5/krb5_child.c:2587 src/providers/ldap/ldap_child.c:590
+#: src/util/util.h:111
 msgid "Debug level"
 msgstr "Nivell de depuració"
 
-#: src/providers/krb5/krb5_child.c:2594 src/providers/ldap/ldap_child.c:611
-#: src/util/util.h:116
+#: src/providers/krb5/krb5_child.c:2589 src/providers/ldap/ldap_child.c:592
+#: src/util/util.h:117
 msgid "Add debug timestamps"
 msgstr "Afegeix marques de temps de depuració"
 
-#: src/providers/krb5/krb5_child.c:2596 src/providers/ldap/ldap_child.c:613
-#: src/util/util.h:118
+#: src/providers/krb5/krb5_child.c:2591 src/providers/ldap/ldap_child.c:594
+#: src/util/util.h:119
 msgid "Show timestamps with microseconds"
 msgstr "Mostra les marques de temps amb microsegons"
 
-#: src/providers/krb5/krb5_child.c:2598 src/providers/ldap/ldap_child.c:615
+#: src/providers/krb5/krb5_child.c:2593 src/providers/ldap/ldap_child.c:596
 msgid "An open file descriptor for the debug logs"
 msgstr "Un descriptor de fitxer obert pels registres de depuració"
 
-#: src/providers/krb5/krb5_child.c:2601 src/providers/ldap/ldap_child.c:617
-#: src/util/util.h:114
+#: src/providers/krb5/krb5_child.c:2596 src/providers/ldap/ldap_child.c:598
+#: src/util/util.h:115
 msgid "Send the debug output to stderr directly."
 msgstr "Envia directament la sortida de depuració al stderr."
 
-#: src/providers/krb5/krb5_child.c:2603
+#: src/providers/krb5/krb5_child.c:2598
 msgid "The user to create FAST ccache as"
 msgstr ""
 
-#: src/providers/krb5/krb5_child.c:2605
+#: src/providers/krb5/krb5_child.c:2600
 msgid "The group to create FAST ccache as"
 msgstr ""
 
-#: src/providers/data_provider_be.c:2833
+#: src/providers/data_provider_be.c:2923
 msgid "Domain of the information provider (mandatory)"
 msgstr "Domini del proveïdor d'informació (obligatori)"
 
@@ -1418,83 +1437,83 @@ msgstr "Error inesperat en cercar una descripció de l'error"
 msgid "Permission denied. "
 msgstr ""
 
-#: src/sss_client/pam_sss.c:67 src/sss_client/pam_sss.c:728
-#: src/sss_client/pam_sss.c:739
+#: src/sss_client/pam_sss.c:67 src/sss_client/pam_sss.c:734
+#: src/sss_client/pam_sss.c:745
 msgid "Server message: "
 msgstr "Missatge del servidor: "
 
-#: src/sss_client/pam_sss.c:246
+#: src/sss_client/pam_sss.c:252
 msgid "Passwords do not match"
 msgstr "Les contrasenyes no coincideixen"
 
-#: src/sss_client/pam_sss.c:434
+#: src/sss_client/pam_sss.c:440
 msgid "Password reset by root is not supported."
 msgstr "La reinicialització de la contrasenya pel root no està suportada."
 
-#: src/sss_client/pam_sss.c:475
+#: src/sss_client/pam_sss.c:481
 msgid "Authenticated with cached credentials"
 msgstr "S'ha autenticat amb credencials en la memòria auxiliar"
 
-#: src/sss_client/pam_sss.c:476
+#: src/sss_client/pam_sss.c:482
 msgid ", your cached password will expire at: "
 msgstr ", la vostra contrasenya en memòria auxiliar expirarà el: "
 
-#: src/sss_client/pam_sss.c:506
+#: src/sss_client/pam_sss.c:512
 #, c-format
 msgid "Your password has expired. You have %1$d grace login(s) remaining."
 msgstr ""
 "La seva contrasenya ha expirat. Teniu %1$d inici(s) de sessió de gràcia "
 "restants."
 
-#: src/sss_client/pam_sss.c:552
+#: src/sss_client/pam_sss.c:558
 #, c-format
 msgid "Your password will expire in %1$d %2$s."
 msgstr "La vostra contrasenya expirarà en %1$d %2$s."
 
-#: src/sss_client/pam_sss.c:601
+#: src/sss_client/pam_sss.c:607
 msgid "Authentication is denied until: "
 msgstr "S'ha denegat l'autenticació fins: "
 
-#: src/sss_client/pam_sss.c:622
+#: src/sss_client/pam_sss.c:628
 msgid "System is offline, password change not possible"
 msgstr ""
 "El sistema es troba fora de línia, el canvi de contrasenya no és possible"
 
-#: src/sss_client/pam_sss.c:637
+#: src/sss_client/pam_sss.c:643
 msgid ""
 "After changing the OTP password, you need to log out and back in order to "
 "acquire a ticket"
 msgstr ""
 
-#: src/sss_client/pam_sss.c:725 src/sss_client/pam_sss.c:738
+#: src/sss_client/pam_sss.c:731 src/sss_client/pam_sss.c:744
 msgid "Password change failed. "
 msgstr "Ha fallat el canvi de contrasenya."
 
-#: src/sss_client/pam_sss.c:1354
+#: src/sss_client/pam_sss.c:1444
 msgid "New Password: "
 msgstr "Nova contrasenya: "
 
-#: src/sss_client/pam_sss.c:1355
+#: src/sss_client/pam_sss.c:1445
 msgid "Reenter new Password: "
 msgstr "Re-introduïu la nova contrasenya: "
 
-#: src/sss_client/pam_sss.c:1459
+#: src/sss_client/pam_sss.c:1549
 msgid "First Factor: "
 msgstr ""
 
-#: src/sss_client/pam_sss.c:1460
+#: src/sss_client/pam_sss.c:1550
 msgid "Second Factor: "
 msgstr ""
 
-#: src/sss_client/pam_sss.c:1462
+#: src/sss_client/pam_sss.c:1554
 msgid "Password: "
 msgstr "Contrasenya: "
 
-#: src/sss_client/pam_sss.c:1502
+#: src/sss_client/pam_sss.c:1594
 msgid "Current Password: "
 msgstr "Contrasenya actual: "
 
-#: src/sss_client/pam_sss.c:1701
+#: src/sss_client/pam_sss.c:1793
 msgid "Password expired. Change your password now."
 msgstr "La contrasenya ha expirat. Canviau la vostra contrasenya ara."
 
@@ -1599,8 +1618,7 @@ msgstr "Especifica l'usuari a afegir\n"
 #: src/tools/sss_usermod.c:162
 msgid "Error initializing the tools - no local domain\n"
 msgstr ""
-"S'ha produït un error en inicialitzar les eines - no hi ha cap domini "
-"local\n"
+"S'ha produït un error en inicialitzar les eines - no hi ha cap domini local\n"
 
 #: src/tools/sss_useradd.c:123 src/tools/sss_groupadd.c:88
 #: src/tools/sss_groupdel.c:82 src/tools/sss_groupmod.c:115
@@ -1720,8 +1738,8 @@ msgstr ""
 
 #: src/tools/sss_groupdel.c:132
 msgid ""
-"No such group in local domain. Removing groups only allowed in local domain."
-"\n"
+"No such group in local domain. Removing groups only allowed in local "
+"domain.\n"
 msgstr ""
 "No existeix el grup al domini local. L'eliminació de grups només es permet "
 "al domini local.\n"
@@ -1805,16 +1823,20 @@ msgstr "%1$sUsuaris membre: "
 
 #: src/tools/sss_groupshow.c:610
 #, c-format
-msgid "\n"
+msgid ""
+"\n"
 "%1$sIs a member of: "
-msgstr "\n"
+msgstr ""
+"\n"
 "%1$sÉs un membre de: "
 
 #: src/tools/sss_groupshow.c:617
 #, c-format
-msgid "\n"
+msgid ""
+"\n"
 "%1$sMember groups: "
-msgstr "\n"
+msgstr ""
+"\n"
 "%1$sGrups membre: "
 
 #: src/tools/sss_groupshow.c:653
@@ -1827,8 +1849,8 @@ msgstr "Especifica el grup a mostrar\n"
 
 #: src/tools/sss_groupshow.c:727
 msgid ""
-"No such group in local domain. Printing groups only allowed in local domain."
-"\n"
+"No such group in local domain. Printing groups only allowed in local "
+"domain.\n"
 msgstr ""
 "No s'ha trobat el grup al domini local. L'impressió de grups només es permet "
 "al domini local.\n"
@@ -1870,8 +1892,8 @@ msgstr "No es pot reiniciar el context d'inici de sessió de SELinux\n"
 #, c-format
 msgid "WARNING: The user (uid %1$lu) was still logged in when deleted.\n"
 msgstr ""
-"ATENCIÓ: L'usuari (uid %1$lu) encara estava en la sessió quan es va eliminar."
-"\n"
+"ATENCIÓ: L'usuari (uid %1$lu) encara estava en la sessió quan es va "
+"eliminar.\n"
 
 #: src/tools/sss_userdel.c:276
 msgid "Cannot determine if the user was logged in on this platform"
@@ -2090,14 +2112,14 @@ msgstr "Sense memòria\n"
 msgid "%1$s must be run as root\n"
 msgstr "S'ha d'executar %1$s com a root\n"
 
-#: src/util/util.h:112
+#: src/util/util.h:113
 msgid "Send the debug output to files instead of stderr"
 msgstr "Envia la sortida de depuració a fitxers en lloc del stderr"
 
-#: src/util/util.h:182
+#: src/util/util.h:183
 msgid "The user ID to run the server as"
 msgstr ""
 
-#: src/util/util.h:184
+#: src/util/util.h:185
 msgid "The group ID to run the server as"
 msgstr ""
diff --git a/src/responder/secrets/local.c b/src/responder/secrets/local.c
index f8e3360b9dc8336b93e512514790c474de6c0b55..94e1fac43c2d58fd7e54e6041b289684ec77d588 100644
--- a/src/responder/secrets/local.c
+++ b/src/responder/secrets/local.c
@@ -20,9 +20,75 @@
 */
 
 #include "responder/secrets/secsrv_private.h"
+#include "util/crypto/sss_crypto.h"
 #include <ldb.h>
 
+#define MKEY_SIZE (256 / 8)
 
+struct local_context {
+    struct ldb_context *ldb;
+    struct sec_data master_key;
+};
+
+int local_decrypt(struct local_context *lctx, TALLOC_CTX *mem_ctx,
+                  const char *secret, const char *enctype,
+                  char **plain_secret)
+{
+    char *output;
+
+    if (enctype && strcmp(enctype, "masterkey") == 0) {
+        struct sec_data _secret;
+        size_t outlen;
+        int ret;
+
+        _secret.data = (char *)sss_base64_decode(mem_ctx, secret,
+                                                 &_secret.length);
+        if (!_secret.data) return EINVAL;
+
+        ret = sss_decrypt(mem_ctx, AES256CBC_HMAC_SHA256,
+                          (uint8_t *)lctx->master_key.data,
+                          lctx->master_key.length,
+                          (uint8_t *)_secret.data, _secret.length,
+                          (uint8_t **)&output, &outlen);
+        if (ret) return ret;
+
+        if (((strnlen(output, outlen) + 1) != outlen) ||
+            output[outlen - 1] != '\0') {
+            return EIO;
+        }
+    } else {
+        output = talloc_strdup(mem_ctx, secret);
+        if (!output) return ENOMEM;
+    }
+
+    *plain_secret = output;
+    return EOK;
+}
+
+int local_encrypt(struct local_context *lctx, TALLOC_CTX *mem_ctx,
+                  const char *secret, const char *enctype,
+                  char **ciphertext)
+{
+    struct sec_data _secret;
+    char *output;
+    int ret;
+
+    if (!enctype || strcmp(enctype, "masterkey") != 0) return EINVAL;
+
+    ret = sss_encrypt(mem_ctx, AES256CBC_HMAC_SHA256,
+                      (uint8_t *)lctx->master_key.data,
+                      lctx->master_key.length,
+                      (const uint8_t *)secret, strlen(secret) + 1,
+                      (uint8_t **)&_secret.data, &_secret.length);
+    if (ret) return ret;
+
+    output = sss_base64_encode(mem_ctx,
+                               (uint8_t *)_secret.data, _secret.length);
+    if (!output) return ENOMEM;
+
+    *ciphertext = output;
+    return EOK;
+}
 
 int local_db_dn(TALLOC_CTX *mem_ctx,
                 struct ldb_context *ldb,
@@ -101,25 +167,26 @@ char *local_dn_to_path(TALLOC_CTX *mem_ctx,
 }
 
 int local_db_get_simple(TALLOC_CTX *mem_ctx,
-                        struct ldb_context *ldb,
+                        struct local_context *lctx,
                         const char *req_path,
                         char **secret)
 {
     TALLOC_CTX *tmp_ctx;
-    static const char *attrs[] = { "secret", NULL };
+    static const char *attrs[] = { "secret", "enctype", NULL };
     const char *filter = "(type=simple)";
     struct ldb_result *res;
     struct ldb_dn *dn;
     const char *attr_secret;
+    const char *attr_enctype;
     int ret;
 
     tmp_ctx = talloc_new(mem_ctx);
     if (!tmp_ctx) return ENOMEM;
 
-    ret = local_db_dn(tmp_ctx, ldb, req_path, &dn);
+    ret = local_db_dn(tmp_ctx, lctx->ldb, req_path, &dn);
     if (ret != EOK) goto done;
 
-    ret = ldb_search(ldb, tmp_ctx, &res, dn, LDB_SCOPE_BASE,
+    ret = ldb_search(lctx->ldb, tmp_ctx, &res, dn, LDB_SCOPE_BASE,
                      attrs, filter);
     if (ret != EOK) {
         ret = ENOENT;
@@ -143,7 +210,14 @@ int local_db_get_simple(TALLOC_CTX *mem_ctx,
         goto done;
     }
 
-    *secret = talloc_strdup(mem_ctx, attr_secret);
+    attr_enctype = ldb_msg_find_attr_as_string(res->msgs[0], "enctype", NULL);
+
+    if (attr_enctype) {
+        ret = local_decrypt(lctx, mem_ctx, attr_secret, attr_enctype, secret);
+        if (ret) goto done;
+    } else {
+        *secret = talloc_strdup(mem_ctx, attr_secret);
+    }
     ret = EOK;
 
 done:
@@ -152,7 +226,7 @@ done:
 }
 
 int local_db_list_keys(TALLOC_CTX *mem_ctx,
-                       struct ldb_context *ldb,
+                       struct local_context *lctx,
                        const char *req_path,
                        char ***_keys,
                        int *num_keys)
@@ -168,10 +242,10 @@ int local_db_list_keys(TALLOC_CTX *mem_ctx,
     tmp_ctx = talloc_new(mem_ctx);
     if (!tmp_ctx) return ENOMEM;
 
-    ret = local_db_dn(tmp_ctx, ldb, req_path, &dn);
+    ret = local_db_dn(tmp_ctx, lctx->ldb, req_path, &dn);
     if (ret != EOK) goto done;
 
-    ret = ldb_search(ldb, tmp_ctx, &res, dn, LDB_SCOPE_SUBTREE,
+    ret = ldb_search(lctx->ldb, tmp_ctx, &res, dn, LDB_SCOPE_SUBTREE,
                      attrs, filter);
     if (ret != EOK) {
         ret = ENOENT;
@@ -207,11 +281,13 @@ done:
 }
 
 int local_db_put_simple(TALLOC_CTX *mem_ctx,
-                        struct ldb_context *ldb,
+                        struct local_context *lctx,
                         const char *req_path,
                         const char *secret)
 {
     struct ldb_message *msg;
+    const char *enctype = "masterkey";
+    char *enc_secret;
     int ret;
 
     msg = ldb_msg_new(mem_ctx);
@@ -220,16 +296,24 @@ int local_db_put_simple(TALLOC_CTX *mem_ctx,
         goto done;
     }
 
-    ret = local_db_dn(msg, ldb, req_path, &msg->dn);
+    /* FIXME: verify containers (except for user's namespace) exists */
+
+    ret = local_encrypt(lctx, msg, secret, enctype, &enc_secret);
+    if (ret != EOK) goto done;
+
+    ret = local_db_dn(msg, lctx->ldb, req_path, &msg->dn);
     if (ret != EOK) goto done;
 
     ret = ldb_msg_add_string(msg, "type", "simple");
     if (ret != EOK) goto done;
 
-    ret = ldb_msg_add_string(msg, "secret", secret);
+    ret = ldb_msg_add_string(msg, "enctype", enctype);
     if (ret != EOK) goto done;
 
-    ret = ldb_add(ldb, msg);
+    ret = ldb_msg_add_string(msg, "secret", enc_secret);
+    if (ret != EOK) goto done;
+
+    ret = ldb_add(lctx->ldb, msg);
     if (ret != EOK) {
         if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) ret = EEXIST;
         else ret = EIO;
@@ -244,16 +328,16 @@ done:
 }
 
 int local_db_delete(TALLOC_CTX *mem_ctx,
-                    struct ldb_context *ldb,
+                    struct local_context *lctx,
                     const char *req_path)
 {
     struct ldb_dn *dn;
     int ret;
 
-    ret = local_db_dn(mem_ctx, ldb, req_path, &dn);
+    ret = local_db_dn(mem_ctx, lctx->ldb, req_path, &dn);
     if (ret != EOK) goto done;
 
-    ret = ldb_delete(ldb, dn);
+    ret = ldb_delete(lctx->ldb, dn);
     if (ret != EOK) {
         ret = EIO;
     }
@@ -319,7 +403,7 @@ struct tevent_req *local_secret_req(TALLOC_CTX *mem_ctx,
 {
     struct tevent_req *req;
     struct local_secret_state *state;
-    struct ldb_context *ldb;
+    struct local_context *lctx;
     struct sec_data body = { 0 };
     char *req_path;
     char *secret;
@@ -333,8 +417,8 @@ struct tevent_req *local_secret_req(TALLOC_CTX *mem_ctx,
     state->ev = ev;
     state->secreq = secreq;
 
-    ldb = talloc_get_type(provider_ctx, struct ldb_context);
-    if (!ldb) {
+    lctx = talloc_get_type(provider_ctx, struct local_context);
+    if (!lctx) {
         ret = EIO;
         goto done;
     }
@@ -345,13 +429,13 @@ struct tevent_req *local_secret_req(TALLOC_CTX *mem_ctx,
     switch (secreq->method) {
     case HTTP_GET:
         if (req_path[strlen(req_path) - 1] == '/') {
-            ret = local_db_list_keys(state, ldb, req_path, &keys, &nkeys);
+            ret = local_db_list_keys(state, lctx, req_path, &keys, &nkeys);
             if (ret) goto done;
 
             ret = sec_array_to_json(state, keys, nkeys, &body.data);
             if (ret) goto done;
         } else {
-            ret = local_db_get_simple(state, ldb, req_path, &secret);
+            ret = local_db_get_simple(state, lctx, req_path, &secret);
             if (ret) goto done;
 
             ret = sec_simple_secret_to_json(state, secret, &body.data);
@@ -362,15 +446,17 @@ struct tevent_req *local_secret_req(TALLOC_CTX *mem_ctx,
         break;
 
     case HTTP_PUT:
+        /*FIXME: check fot content-type */
+
         ret = sec_json_to_simple_secret(state, secreq->body.data, &secret);
         if (ret) goto done;
 
-        ret = local_db_put_simple(state, ldb, req_path, secret);
+        ret = local_db_put_simple(state, lctx, req_path, secret);
         if (ret) goto done;
         break;
 
     case HTTP_DELETE:
-        ret = local_db_delete(state, ldb, req_path);
+        ret = local_db_delete(state, lctx, req_path);
         if (ret) goto done;
         break;
 
@@ -397,6 +483,29 @@ done:
     return tevent_req_post(req, state->ev);
 }
 
+int generate_master_key(const char *filename, size_t size)
+{
+    uint8_t buf[size];
+    ssize_t rsize;
+    int ret;
+    int fd;
+
+    ret = generate_csprng_buffer(buf, size);
+    if (ret) return ret;
+
+    fd = open(filename, O_CREAT|O_EXCL|O_WRONLY, 0600);
+    if (fd == -1) return errno;
+
+    rsize = sss_atomic_io_s(fd, buf, size, false);
+    close(fd);
+    if (rsize != size) {
+        unlink(filename);
+        return EFAULT;
+    }
+
+    return EOK;
+}
+
 /* FIXME: allocate on the responder context */
 static struct provider_handle local_secrets_handle = {
     .fn = local_secret_req,
@@ -406,20 +515,46 @@ static struct provider_handle local_secrets_handle = {
 int local_secrets_provider_handle(TALLOC_CTX *mem_ctx,
                                   struct provider_handle **handle)
 {
-    struct ldb_context *ldb;
+    struct local_context *lctx;
     int ret;
 
     if (local_secrets_handle.context == NULL) {
-        ldb = ldb_init(NULL, NULL);
-        if (!ldb) return EIO;
+        const char *mkey = SECRETS_DB_PATH"/.secrets.mkey";
+        ssize_t size;
+        int mfd;
 
-        ret = ldb_connect(ldb, SECRETS_DB_PATH"/secrets.ldb", 0, NULL);
+        lctx = talloc_zero(NULL, struct local_context);
+        if (!lctx) return ENOMEM;
+
+        lctx->ldb = ldb_init(lctx, NULL);
+        if (!lctx->ldb) return ENOMEM;
+
+        ret = ldb_connect(lctx->ldb, SECRETS_DB_PATH"/secrets.ldb", 0, NULL);
         if (ret != LDB_SUCCESS) {
-            talloc_free(ldb);
+            talloc_free(lctx->ldb);
             return EIO;
         }
 
-        local_secrets_handle.context = ldb;
+        lctx->master_key.data = talloc_size(lctx, MKEY_SIZE);
+        if (!lctx->master_key.data) return ENOMEM;
+        lctx->master_key.length = MKEY_SIZE;
+
+        ret = check_and_open_readonly(mkey, &mfd, 0, 0,
+                                      S_IFREG|S_IRUSR|S_IWUSR, 0);
+        if (ret == ENOENT) {
+            ret = generate_master_key(mkey, MKEY_SIZE);
+            if (ret) return EFAULT;
+            ret = check_and_open_readonly(mkey, &mfd, 0, 0,
+                                          S_IFREG|S_IRUSR|S_IWUSR, 0);
+        }
+        if (ret) return EFAULT;
+
+        size = sss_atomic_io_s(mfd, lctx->master_key.data,
+                               lctx->master_key.length, true);
+        close(mfd);
+        if (size < 0 || size != lctx->master_key.length) return EIO;
+
+        local_secrets_handle.context = lctx;
     }
 
     *handle = &local_secrets_handle;
diff --git a/src/responder/secrets/secsrv_local.h b/src/responder/secrets/secsrv_local.h
index 537f61e53d098deecbc2530e9e3c21a07eaecada..d21b14953b0497a17f7b0b7730a3e1529f928aea 100644
--- a/src/responder/secrets/secsrv_local.h
+++ b/src/responder/secrets/secsrv_local.h
@@ -1,7 +1,7 @@
 /*
    SSSD
 
-   Secrets Local Provider
+   Secrets Proxy Provider
 
    Copyright (C) Simo Sorce <ssorce@redhat.com>	2016
 
diff --git a/src/util/crypto/libcrypto/crypto_nite.c b/src/util/crypto/libcrypto/crypto_nite.c
new file mode 100644
index 0000000000000000000000000000000000000000..f0660da389e8f140ed645364a0abdd977331b8d7
--- /dev/null
+++ b/src/util/crypto/libcrypto/crypto_nite.c
@@ -0,0 +1,226 @@
+/*
+   SSSD
+
+   Encryption/Decryption primitives
+
+   Authors:
+       Simo Sorce <simo@redhat.com>
+
+   Copyright (C) Simo Sorce 2016
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "config.h"
+#include <talloc.h>
+#include <errno.h>
+
+#include "util/util.h"
+#include "util/crypto/sss_crypto.h"
+
+#include <openssl/evp.h>
+#include <openssl/rand.h>
+#include <openssl/crypto.h>
+
+struct cipher_mech {
+    const EVP_CIPHER * (*cipher)(void);
+    const EVP_MD * (*digest)(void);
+} mechs[] = {
+    { EVP_aes_256_cbc, EVP_sha256 }
+};
+
+#define GOTO_IF_NOT_EQUAL(res, exp, ret, err, label) \
+    if (res != exp) { ret = err; goto label; }
+
+int sss_encrypt(TALLOC_CTX *mem_ctx, enum encmethod enctype,
+                uint8_t *key, size_t keylen,
+                const uint8_t *plaintext, size_t plainlen,
+                uint8_t **ciphertext, size_t *cipherlen)
+{
+    const EVP_CIPHER *cipher;
+    const EVP_MD *digest;
+    EVP_PKEY *hmackey;
+    EVP_CIPHER_CTX ctx;
+    EVP_MD_CTX mdctx;
+    uint8_t *out = NULL;
+    int evpkeylen;
+    int evpivlen;
+    int hmaclen;
+    int outlen, tmplen;
+    size_t slen;
+    int ret;
+
+    if (!plaintext || !plainlen) return EINVAL;
+
+    if (enctype != AES256CBC_HMAC_SHA256) return EINVAL;
+    cipher = mechs[AES256CBC_HMAC_SHA256].cipher();
+    digest = mechs[AES256CBC_HMAC_SHA256].digest();
+
+    evpkeylen = EVP_CIPHER_key_length(cipher);
+    if (!key || keylen != evpkeylen) return EINVAL;
+
+    hmackey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, key, keylen);
+    if (!hmackey) return ENOMEM;
+
+    /* We have no function to return the size of the output for arbitray HMAC
+     * algorithms so we just truncate to the key size should the hmac be bigger
+     * (or pad with zeros should the HMAC be smaller) */
+    hmaclen = keylen;
+
+    evpivlen = EVP_CIPHER_iv_length(cipher);
+    outlen = plainlen + (2 * EVP_CIPHER_block_size(cipher))
+                + evpivlen + hmaclen;
+    out = talloc_zero_size(mem_ctx, outlen);
+
+    /* First Encrypt */
+
+    if (evpivlen != 0) {
+        RAND_bytes(out, evpivlen);
+    }
+
+    EVP_CIPHER_CTX_init(&ctx);
+    ret = EVP_EncryptInit_ex(&ctx, cipher, 0, key, evpivlen ? out : NULL);
+    GOTO_IF_NOT_EQUAL(ret, 1, ret, EFAULT, done);
+
+    outlen = evpivlen;
+    tmplen = 0;
+    ret = EVP_EncryptUpdate(&ctx, out + outlen, &tmplen, plaintext, plainlen);
+    GOTO_IF_NOT_EQUAL(ret, 1, ret, EFAULT, done);
+
+    outlen += tmplen;
+
+    ret = EVP_EncryptFinal_ex(&ctx, out + outlen, &tmplen);
+    GOTO_IF_NOT_EQUAL(ret, 1, ret, EFAULT, done);
+
+    outlen += tmplen;
+
+    /* Then HMAC */
+
+    EVP_MD_CTX_init(&mdctx);
+
+    ret = EVP_DigestInit_ex(&mdctx, digest, NULL);
+    GOTO_IF_NOT_EQUAL(ret, 1, ret, EFAULT, done);
+
+    ret = EVP_DigestSignInit(&mdctx, NULL, digest, NULL, hmackey);
+    GOTO_IF_NOT_EQUAL(ret, 1, ret, EFAULT, done);
+
+    ret = EVP_DigestSignUpdate(&mdctx, out, outlen);
+    GOTO_IF_NOT_EQUAL(ret, 1, ret, EFAULT, done);
+
+    slen = hmaclen;
+    ret = EVP_DigestSignFinal(&mdctx, &out[outlen], &slen);
+    GOTO_IF_NOT_EQUAL(ret, 1, ret, EFAULT, done);
+
+    outlen += hmaclen;
+
+    *ciphertext = out;
+    *cipherlen = outlen;
+    ret = EOK;
+
+done:
+    EVP_MD_CTX_cleanup(&mdctx);
+    EVP_CIPHER_CTX_cleanup(&ctx);
+    EVP_PKEY_free(hmackey);
+    return ret;
+}
+
+int sss_decrypt(TALLOC_CTX *mem_ctx, enum encmethod enctype,
+                uint8_t *key, size_t keylen,
+                const uint8_t *ciphertext, size_t cipherlen,
+                uint8_t **plaintext, size_t *plainlen)
+{
+    const EVP_CIPHER *cipher;
+    const EVP_MD *digest;
+    EVP_PKEY *hmackey;
+    EVP_CIPHER_CTX ctx;
+    EVP_MD_CTX mdctx;
+    const uint8_t *iv = NULL;
+    uint8_t *out;
+    int evpkeylen;
+    int evpivlen;
+    int hmaclen;
+    int outlen, tmplen;
+    size_t slen;
+    int ret;
+
+    if (!ciphertext || !cipherlen) return EINVAL;
+
+    if (enctype != AES256CBC_HMAC_SHA256) return EINVAL;
+    cipher = mechs[AES256CBC_HMAC_SHA256].cipher();
+    digest = mechs[AES256CBC_HMAC_SHA256].digest();
+
+    evpkeylen = EVP_CIPHER_key_length(cipher);
+    if (!key || keylen != evpkeylen) return EINVAL;
+
+    hmackey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, key, keylen);
+    if (!hmackey) return ENOMEM;
+
+    /* We have no function to return the size of the output for arbitray HMAC
+     * algorithms so we just assume it was truncated to the key size should
+     * the hmac be bigger (or pad with zeros should the HMAC be smaller) */
+    hmaclen = keylen;
+
+    evpivlen = EVP_CIPHER_iv_length(cipher);
+    out = talloc_zero_size(mem_ctx, cipherlen);
+
+    /* First check HMAC */
+
+    EVP_MD_CTX_init(&mdctx);
+
+    ret = EVP_DigestInit_ex(&mdctx, digest, NULL);
+    GOTO_IF_NOT_EQUAL(ret, 1, ret, EFAULT, done);
+
+    ret = EVP_DigestSignInit(&mdctx, NULL, digest, NULL, hmackey);
+    GOTO_IF_NOT_EQUAL(ret, 1, ret, EFAULT, done);
+
+    ret = EVP_DigestSignUpdate(&mdctx, ciphertext, cipherlen - hmaclen);
+    GOTO_IF_NOT_EQUAL(ret, 1, ret, EFAULT, done);
+
+    slen = hmaclen;
+    ret = EVP_DigestSignFinal(&mdctx, out, &slen);
+    GOTO_IF_NOT_EQUAL(ret, 1, ret, EFAULT, done);
+
+    ret = CRYPTO_memcmp(&ciphertext[cipherlen - hmaclen], out, hmaclen);
+    GOTO_IF_NOT_EQUAL(ret, 0, ret, EFAULT, done);
+
+    /* Then Decrypt */
+
+    if (evpivlen != 0) {
+        iv = ciphertext;
+    }
+
+    EVP_CIPHER_CTX_init(&ctx);
+    ret = EVP_DecryptInit_ex(&ctx, cipher, 0, key, iv);
+    GOTO_IF_NOT_EQUAL(ret, 1, ret, EFAULT, done);
+
+    ret = EVP_DecryptUpdate(&ctx, out, &outlen,
+                            ciphertext + evpivlen,
+                            cipherlen - evpivlen - hmaclen);
+    GOTO_IF_NOT_EQUAL(ret, 1, ret, EFAULT, done);
+
+    ret = EVP_DecryptFinal_ex(&ctx, out + outlen, &tmplen);
+    GOTO_IF_NOT_EQUAL(ret, 1, ret, EFAULT, done);
+
+    outlen += tmplen;
+
+    *plaintext = out;
+    *plainlen = outlen;
+    ret = EOK;
+
+done:
+    EVP_MD_CTX_cleanup(&mdctx);
+    EVP_CIPHER_CTX_cleanup(&ctx);
+    EVP_PKEY_free(hmackey);
+    return ret;
+}
diff --git a/src/util/crypto/nss/nss_crypto.h b/src/util/crypto/nss/nss_crypto.h
new file mode 100644
index 0000000000000000000000000000000000000000..c6c0ea8e7fc78bbe9378abdcccf2ffd00278f732
--- /dev/null
+++ b/src/util/crypto/nss/nss_crypto.h
@@ -0,0 +1,67 @@
+/*
+   SSSD
+
+   NSS crypto wrappers
+
+   Authors:
+        Jakub Hrozek <jhrozek@redhat.com>
+
+   Copyright (C) Red Hat, Inc 2010
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <nss.h>
+#include <prerror.h>
+#include <pk11func.h>
+#include <base64.h>
+#include <talloc.h>
+
+#define MAKE_SECITEM(sdata, slen, sitem) do { \
+    (sitem)->type = (siBuffer); \
+    (sitem)->data = (sdata);    \
+    (sitem)->len  = (slen);     \
+} while(0)
+
+struct sss_nss_crypto_ctx {
+    PK11SlotInfo *slot;
+    PK11Context  *ectx;
+    PK11SymKey   *keyobj;
+    SECItem      *sparam;
+
+    SECItem      *iv;
+    SECItem      *key;
+};
+
+struct crypto_mech_data {
+    CK_MECHANISM_TYPE cipher;
+    uint16_t keylen;
+    uint16_t bsize;
+};
+
+enum crypto_mech_op {
+    op_encrypt,
+    op_decrypt,
+    op_sign
+};
+
+int nss_ctx_init(TALLOC_CTX *mem_ctx,
+                 struct crypto_mech_data *mech_props,
+                 uint8_t *key, int keylen,
+                 uint8_t *iv, int ivlen,
+                 struct sss_nss_crypto_ctx **_cctx);
+int nss_crypto_init(struct crypto_mech_data *mech_props,
+                    enum crypto_mech_op crypto_op,
+                    struct sss_nss_crypto_ctx *cctx);
+
diff --git a/src/util/crypto/nss/nss_nite.c b/src/util/crypto/nss/nss_nite.c
new file mode 100644
index 0000000000000000000000000000000000000000..7ebdbac4a23a9c8d830d24782ca4906c3ef7cc98
--- /dev/null
+++ b/src/util/crypto/nss/nss_nite.c
@@ -0,0 +1,245 @@
+/*
+   SSSD
+
+   Encryption/Decryption primitives
+
+   Authors:
+       Simo Sorce <simo@redhat.com>
+
+   Copyright (C) Simo Sorce 2016
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "config.h"
+
+#include "util/util.h"
+#include "util/crypto/sss_crypto.h"
+#include "util/crypto/nss/nss_util.h"
+#include "util/crypto/nss/nss_crypto.h"
+
+struct cipher_mech {
+    struct crypto_mech_data enc;
+    struct crypto_mech_data hmac;
+} mechs[] = {
+    { { CKM_AES_CBC_PAD, 32, 16 }, { CKM_SHA256_HMAC, 32, 16 } }
+};
+
+#define GOTO_IF_NOT_EQUAL(res, exp, ret, err, label) \
+    if (res != exp) { ret = err; goto label; }
+
+int sss_encrypt(TALLOC_CTX *mem_ctx, enum encmethod enctype,
+                uint8_t *key, size_t keylen,
+                const uint8_t *plaintext, size_t plainlen,
+                uint8_t **ciphertext, size_t *cipherlen)
+{
+    TALLOC_CTX *tmp_ctx = NULL;
+    struct sss_nss_crypto_ctx *cctx;
+    struct sss_nss_crypto_ctx *hctx;
+    struct crypto_mech_data *enc;
+    struct crypto_mech_data *hmac;
+    SECStatus sret;
+    uint8_t *out = NULL;
+    int ivlen;
+    int hmaclen;
+    int outlen;
+    int clen;
+    union {
+        unsigned int u;
+        int s;
+    } tmplen;
+    unsigned int digestlen;
+    int ret;
+
+    if (!plaintext || !plainlen) return EINVAL;
+
+    if (enctype != AES256CBC_HMAC_SHA256) return EINVAL;
+    enc = &mechs[AES256CBC_HMAC_SHA256].enc;
+    hmac = &mechs[AES256CBC_HMAC_SHA256].hmac;
+    ivlen = enc->bsize;
+
+    /* We have no function to return the size of the output for arbitray HMAC
+     * algorithms so we just truncate to the key size should the hmac be bigger
+     * (or pad with zeros should the HMAC be smaller) */
+    hmaclen = keylen;
+
+    tmp_ctx = talloc_new(mem_ctx);
+    if (!tmp_ctx) {
+        return ENOMEM;
+    }
+
+    /* initialize NSS if needed */
+    ret = nspr_nss_init();
+    GOTO_IF_NOT_EQUAL(ret, EOK, ret, EFAULT, done);
+
+    outlen = plainlen + (2 * enc->bsize) + ivlen + hmaclen;
+    out = talloc_zero_size(tmp_ctx, outlen);
+
+    /* First Encrypt */
+
+    if (ivlen != 0) {
+        ret = generate_csprng_buffer(out, ivlen);
+        if (ret) return ret;
+    }
+
+    ret = nss_ctx_init(tmp_ctx, enc, key, keylen, out, ivlen, &cctx);
+    GOTO_IF_NOT_EQUAL(ret, EOK, ret, EFAULT, done);
+
+    ret = nss_crypto_init(enc, op_encrypt, cctx);
+    GOTO_IF_NOT_EQUAL(ret, EOK, ret, EFAULT, done);
+
+    clen = ivlen;
+
+    sret = PK11_CipherOp(cctx->ectx, out + clen, &tmplen.s,
+                         outlen - clen, plaintext, plainlen);
+    GOTO_IF_NOT_EQUAL(sret, SECSuccess, ret, EFAULT, done);
+
+    clen += tmplen.s;
+
+    sret = PK11_DigestFinal(cctx->ectx, out + clen, &tmplen.u, outlen - clen);
+    GOTO_IF_NOT_EQUAL(sret, SECSuccess, ret, EFAULT, done);
+
+    clen += tmplen.u;
+    if (clen < 0 || clen > UINT16_MAX) {
+        ret = ERANGE;
+        goto done;
+    }
+
+    /* Then HMAC */
+
+    ret = nss_ctx_init(tmp_ctx, hmac, key, keylen, NULL, 0, &hctx);
+    GOTO_IF_NOT_EQUAL(ret, EOK, ret, EFAULT, done);
+
+    ret = nss_crypto_init(hmac, op_sign, hctx);
+    GOTO_IF_NOT_EQUAL(ret, EOK, ret, EFAULT, done);
+
+    sret = PK11_DigestBegin(hctx->ectx);
+    GOTO_IF_NOT_EQUAL(sret, SECSuccess, ret, EFAULT, done);
+
+    sret = PK11_DigestOp(hctx->ectx, out, clen);
+    GOTO_IF_NOT_EQUAL(sret, SECSuccess, ret, EFAULT, done);
+
+    sret = PK11_DigestFinal(hctx->ectx, out + clen, &digestlen,
+                            outlen - clen);
+    GOTO_IF_NOT_EQUAL(sret, SECSuccess, ret, EFAULT, done);
+
+    *ciphertext = talloc_move(mem_ctx, &out);
+    *cipherlen = clen + hmaclen;
+    ret = EOK;
+
+done:
+    talloc_free(tmp_ctx);
+    nspr_nss_cleanup();
+    return ret;
+}
+
+int sss_decrypt(TALLOC_CTX *mem_ctx, enum encmethod enctype,
+                uint8_t *key, size_t keylen,
+                const uint8_t *ciphertext, size_t cipherlen,
+                uint8_t **plaintext, size_t *plainlen)
+{
+    TALLOC_CTX *tmp_ctx = NULL;
+    struct sss_nss_crypto_ctx *cctx;
+    struct sss_nss_crypto_ctx *hctx;
+    struct crypto_mech_data *enc;
+    struct crypto_mech_data *hmac;
+    SECStatus sret;
+    uint8_t *out = NULL;
+    uint8_t *ivbuf = NULL;
+    int ivlen;
+    int hmaclen;
+    int outlen;
+    unsigned int tmplen;
+    unsigned int digestlen;
+    int ret;
+
+    if (!plaintext || !plainlen) return EINVAL;
+
+    if (enctype != AES256CBC_HMAC_SHA256) return EINVAL;
+    enc = &mechs[AES256CBC_HMAC_SHA256].enc;
+    hmac = &mechs[AES256CBC_HMAC_SHA256].hmac;
+    ivlen = enc->bsize;
+
+    /* We have no function to return the size of the output for arbitray HMAC
+     * algorithms so we just truncate to the key size should the hmac be bigger
+     * (or pad with zeros should the HMAC be smaller) */
+    hmaclen = keylen;
+
+    tmp_ctx = talloc_new(mem_ctx);
+    if (!tmp_ctx) {
+        return ENOMEM;
+    }
+
+    /* initialize NSS if needed */
+    ret = nspr_nss_init();
+    GOTO_IF_NOT_EQUAL(ret, EOK, ret, EFAULT, done);
+
+    out = talloc_zero_size(tmp_ctx, cipherlen);
+
+    /* First check HMAC */
+
+    ret = nss_ctx_init(tmp_ctx, hmac, key, keylen, NULL, 0, &hctx);
+    GOTO_IF_NOT_EQUAL(ret, EOK, ret, EFAULT, done);
+
+    ret = nss_crypto_init(hmac, op_sign, hctx);
+    GOTO_IF_NOT_EQUAL(ret, EOK, ret, EFAULT, done);
+
+    sret = PK11_DigestBegin(hctx->ectx);
+    GOTO_IF_NOT_EQUAL(sret, SECSuccess, ret, EFAULT, done);
+
+    sret = PK11_DigestOp(hctx->ectx, ciphertext, cipherlen - hmaclen);
+    GOTO_IF_NOT_EQUAL(sret, SECSuccess, ret, EFAULT, done);
+
+    sret = PK11_DigestFinal(hctx->ectx, out, &digestlen, hmaclen);
+    GOTO_IF_NOT_EQUAL(sret, SECSuccess, ret, EFAULT, done);
+
+    ret = NSS_SecureMemcmp(&ciphertext[cipherlen - hmaclen], out, hmaclen);
+    GOTO_IF_NOT_EQUAL(ret, 0, ret, EFAULT, done);
+
+    /* Then Decrypt */
+
+    if (ivlen != 0) {
+        ivbuf = talloc_size(tmp_ctx, ivlen);
+        if (!ivbuf) {
+            ret = ENOMEM;
+            goto done;
+        }
+        memcpy(ivbuf, ciphertext, ivlen);
+    }
+
+    ret = nss_ctx_init(tmp_ctx, enc, key, keylen, ivbuf, ivlen, &cctx);
+    GOTO_IF_NOT_EQUAL(ret, EOK, ret, EFAULT, done);
+
+    ret = nss_crypto_init(enc, op_decrypt, cctx);
+    GOTO_IF_NOT_EQUAL(ret, EOK, ret, EFAULT, done);
+
+    sret = PK11_CipherOp(cctx->ectx, out, &outlen, cipherlen,
+                         ciphertext + ivlen, cipherlen - ivlen - hmaclen);
+    GOTO_IF_NOT_EQUAL(sret, SECSuccess, ret, EFAULT, done);
+
+    sret = PK11_DigestFinal(cctx->ectx, out + outlen, &tmplen,
+                            cipherlen - outlen);
+    GOTO_IF_NOT_EQUAL(sret, SECSuccess, ret, EFAULT, done);
+
+    outlen += tmplen;
+
+    *plaintext = talloc_move(mem_ctx, &out);
+    *plainlen = outlen;
+    ret = EOK;
+
+done:
+    talloc_free(tmp_ctx);
+    nspr_nss_cleanup();
+    return ret;
+}
diff --git a/src/util/crypto/nss/nss_obfuscate.c b/src/util/crypto/nss/nss_obfuscate.c
index 8c6bdc52524ad7f7a491603e9fd2902fdf9eed18..a55f22b6de0cfdf23f4728ccfb8d4e68d155544b 100644
--- a/src/util/crypto/nss/nss_obfuscate.c
+++ b/src/util/crypto/nss/nss_obfuscate.c
@@ -31,42 +31,17 @@
  */
 
 #include "config.h"
-
 #include <prerror.h>
-#include <nss.h>
 #include <pk11func.h>
-#include <base64.h>
-#include <talloc.h>
 
 #include "util/util.h"
 #include "util/crypto/sss_crypto.h"
 #include "util/crypto/nss/nss_util.h"
+#include "util/crypto/nss/nss_crypto.h"
 
 #define OBF_BUFFER_SENTINEL "\0\1\2\3"
 #define OBF_BUFFER_SENTINEL_SIZE    4
 
-#define MAKE_SECITEM(sdata, slen, sitem) do { \
-    (sitem)->type = (siBuffer); \
-    (sitem)->data = (sdata);    \
-    (sitem)->len  = (slen);     \
-} while(0)
-
-struct sss_nss_crypto_ctx {
-    PK11SlotInfo *slot;
-    PK11Context  *ectx;
-    PK11SymKey   *keyobj;
-    SECItem      *sparam;
-
-    SECItem      *iv;
-    SECItem      *key;
-};
-
-struct crypto_mech_data {
-    CK_MECHANISM_TYPE cipher;
-    uint16_t keylen;
-    uint16_t bsize;
-};
-
 static struct crypto_mech_data cmdata[] = {
     /* AES with automatic padding, 256b key, 128b block */
     { CKM_AES_CBC_PAD, 32, 16 },
@@ -83,147 +58,6 @@ static struct crypto_mech_data *get_crypto_mech_data(enum obfmethod meth)
     return &cmdata[meth];
 }
 
-static int generate_random_key(TALLOC_CTX *mem_ctx,
-                               PK11SlotInfo *slot,
-                               struct crypto_mech_data *mech_props,
-                               SECItem **_key)
-{
-    SECStatus sret;
-    SECItem      *randkeydata;
-    SECItem      *key = NULL;
-    PK11SymKey   *randkey;
-    int ret;
-
-    randkey = PK11_KeyGen(slot, mech_props->cipher,
-                          NULL, mech_props->keylen, NULL);
-    if (randkey == NULL) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "Failure to generate key (err %d)\n",
-                  PR_GetError());
-        ret = EIO;
-        goto done;
-    }
-
-    sret = PK11_ExtractKeyValue(randkey);
-    if (sret != SECSuccess) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "Failure to extract key value (err %d)\n",
-                  PR_GetError());
-        ret = EIO;
-        goto done;
-    }
-
-    randkeydata = PK11_GetKeyData(randkey);
-    if (randkeydata == NULL) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "Failure to get key data (err %d)\n",
-                  PR_GetError());
-        ret = EIO;
-        goto done;
-    }
-
-    /* randkeydata is valid until randkey is. Copy with talloc to
-     * get a nice memory hierarchy symmetrical in encrypt
-     * and decrypt case */
-    key = talloc_zero(mem_ctx, SECItem);
-    if (!key) {
-        ret = ENOMEM;
-        goto done;
-    }
-
-    key->data = talloc_memdup(key, randkeydata->data, randkeydata->len);
-    if (!key->data) {
-        ret = ENOMEM;
-        goto done;
-    }
-    key->len = randkeydata->len;
-
-    *_key = key;
-    ret = EOK;
-done:
-    if (ret != EOK) talloc_zfree(key);
-    PK11_FreeSymKey(randkey);
-    return ret;
-}
-
-static int sss_nss_crypto_ctx_destructor(struct sss_nss_crypto_ctx *cctx)
-{
-    if (cctx->ectx) PK11_DestroyContext(cctx->ectx, PR_TRUE);
-    if (cctx->sparam) SECITEM_FreeItem(cctx->sparam, PR_TRUE);
-    if (cctx->slot) PK11_FreeSlot(cctx->slot);
-    if (cctx->keyobj) PK11_FreeSymKey(cctx->keyobj);
-
-    return EOK;
-}
-
-static int nss_ctx_init(TALLOC_CTX *mem_ctx,
-                        struct crypto_mech_data *mech_props,
-                        struct sss_nss_crypto_ctx **_cctx)
-{
-    struct sss_nss_crypto_ctx *cctx;
-    int ret;
-
-    cctx = talloc_zero(mem_ctx, struct sss_nss_crypto_ctx);
-    if (!cctx) {
-        return ENOMEM;
-    }
-    talloc_set_destructor(cctx, sss_nss_crypto_ctx_destructor);
-
-    cctx->slot = PK11_GetBestSlot(mech_props->cipher, NULL);
-    if (cctx->slot == NULL) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to find security device (err %d)\n",
-                  PR_GetError());
-        ret = EIO;
-        goto done;
-    }
-
-    ret = EOK;
-    *_cctx = cctx;
-done:
-    if (ret) talloc_zfree(cctx);
-    return ret;
-}
-
-static int nss_encrypt_decrypt_init(struct crypto_mech_data *mech_props,
-                                    bool do_encrypt,
-                                    struct sss_nss_crypto_ctx *cctx)
-{
-    CK_ATTRIBUTE_TYPE   op;
-    int ret;
-
-    op = do_encrypt ? CKA_ENCRYPT : CKA_DECRYPT;
-
-    /* turn the raw key into a key object */
-    cctx->keyobj = PK11_ImportSymKey(cctx->slot, mech_props->cipher,
-                                     PK11_OriginUnwrap, op, cctx->key, NULL);
-    if (cctx->keyobj == NULL) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "Failure to import key into NSS (err %d)\n",
-                  PR_GetError());
-        ret = EIO;
-        goto done;
-    }
-
-    /* turn the raw IV into a initialization vector object */
-    cctx->sparam = PK11_ParamFromIV(mech_props->cipher, cctx->iv);
-    if (cctx->sparam == NULL) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "Failure to set up PKCS11 param (err %d)\n",
-                  PR_GetError());
-        ret = EIO;
-        goto done;
-    }
-
-    /* Create cipher context */
-    cctx->ectx = PK11_CreateContextBySymKey(mech_props->cipher, op,
-                                            cctx->keyobj, cctx->sparam);
-    if (cctx->ectx == NULL) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create cipher context (err %d)\n",
-                  PORT_GetError());
-        ret = EIO;
-        goto done;
-    }
-
-    ret = EOK;
-done:
-    return ret;
-}
-
 int sss_password_encrypt(TALLOC_CTX *mem_ctx, const char *password, int plen,
                          enum obfmethod meth, char **obfpwd)
 {
@@ -263,27 +97,14 @@ int sss_password_encrypt(TALLOC_CTX *mem_ctx, const char *password, int plen,
         goto done;
     }
 
-    ret = nss_ctx_init(tmp_ctx, mech_props, &cctx);
+    /* Initiualize ctx and generate random encryption and IV key */
+    ret = nss_ctx_init(tmp_ctx, mech_props, NULL, 1, NULL, 1, &cctx);
     if (ret) {
         DEBUG(SSSDBG_CRIT_FAILURE, "Cannot initialize NSS context\n");
         goto done;
     }
 
-    /* generate random encryption and IV key */
-    ret = generate_random_key(cctx, cctx->slot, mech_props, &cctx->key);
-    if (ret != EOK) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "Could not generate encryption key\n");
-        goto done;
-    }
-
-    ret = generate_random_key(cctx, cctx->slot, mech_props, &cctx->iv);
-    if (ret != EOK) {
-        DEBUG(SSSDBG_CRIT_FAILURE,
-              "Could not generate initialization vector\n");
-        goto done;
-    }
-
-    ret = nss_encrypt_decrypt_init(mech_props, true, cctx);
+    ret = nss_crypto_init(mech_props, op_encrypt, cctx);
     if (ret) {
         DEBUG(SSSDBG_CRIT_FAILURE,
               "Cannot initialize NSS context properties\n");
@@ -431,7 +252,8 @@ int sss_password_decrypt(TALLOC_CTX *mem_ctx, char *b64encoded,
     memcpy(sentinel_check,
            obfbuf + p + mech_props->keylen + mech_props->bsize + ctsize,
            OBF_BUFFER_SENTINEL_SIZE);
-    if (memcmp(sentinel_check, OBF_BUFFER_SENTINEL, OBF_BUFFER_SENTINEL_SIZE) != 0) {
+    if (memcmp(sentinel_check,
+               OBF_BUFFER_SENTINEL, OBF_BUFFER_SENTINEL_SIZE) != 0) {
         DEBUG(SSSDBG_FATAL_FAILURE,
               "Obfuscation buffer seems corrupt, aborting\n");
         ret = EFAULT;
@@ -460,23 +282,15 @@ int sss_password_decrypt(TALLOC_CTX *mem_ctx, char *b64encoded,
     }
     safealign_memcpy(cryptotext, obfbuf+p, ctsize, &p);
 
-    ret = nss_ctx_init(tmp_ctx, mech_props, &cctx);
+    ret = nss_ctx_init(tmp_ctx, mech_props,
+                       keybuf, mech_props->keylen,
+                       ivbuf, mech_props->bsize, &cctx);
     if (ret) {
         DEBUG(SSSDBG_CRIT_FAILURE, "Cannot initialize NSS context\n");
         goto done;
     }
 
-    cctx->iv = talloc_zero(cctx, SECItem);
-    cctx->key = talloc_zero(cctx, SECItem);
-    if (!cctx->iv || !cctx->key) {
-        ret = ENOMEM;
-        goto done;
-    }
-
-    MAKE_SECITEM(ivbuf, mech_props->bsize, cctx->iv);
-    MAKE_SECITEM(keybuf, mech_props->keylen, cctx->key);
-
-    ret = nss_encrypt_decrypt_init(mech_props, false, cctx);
+    ret = nss_crypto_init(mech_props, op_decrypt, cctx);
     if (ret) {
         goto done;
     }
@@ -487,8 +301,8 @@ int sss_password_decrypt(TALLOC_CTX *mem_ctx, char *b64encoded,
         goto done;
     }
 
-    sret = PK11_CipherOp(cctx->ectx, (unsigned char *) pwdbuf, &plainlen, ctsize,
-                         cryptotext, ctsize);
+    sret = PK11_CipherOp(cctx->ectx, (unsigned char *) pwdbuf, &plainlen,
+                         ctsize, cryptotext, ctsize);
     if (sret != SECSuccess) {
         DEBUG(SSSDBG_CRIT_FAILURE,
               "Cannot execute the encryption operation (err %d)\n",
@@ -497,8 +311,8 @@ int sss_password_decrypt(TALLOC_CTX *mem_ctx, char *b64encoded,
         goto done;
     }
 
-    sret = PK11_DigestFinal(cctx->ectx, (unsigned char *) pwdbuf+plainlen, &digestlen,
-                            ctsize - plainlen);
+    sret = PK11_DigestFinal(cctx->ectx, (unsigned char *) pwdbuf+plainlen,
+                            &digestlen, ctsize - plainlen);
     if (sret != SECSuccess) {
         DEBUG(SSSDBG_CRIT_FAILURE,
               "Cannot execute the encryption operation (err %d)\n",
diff --git a/src/util/crypto/nss/nss_util.c b/src/util/crypto/nss/nss_util.c
index 55b81c9b1c8e92e7a16348767a589eb8c92e9330..46835057b04e587b77aed4479c0243522819fd94 100644
--- a/src/util/crypto/nss/nss_util.c
+++ b/src/util/crypto/nss/nss_util.c
@@ -26,12 +26,11 @@
 #include "config.h"
 
 #include <prinit.h>
-#include <prerror.h>
 #include <nss.h>
-#include <pk11func.h>
 
 #include "util/util.h"
 #include "util/crypto/nss/nss_util.h"
+#include "util/crypto/nss/nss_crypto.h"
 
 static int nspr_nss_init_done = 0;
 
@@ -75,3 +74,211 @@ int nspr_nss_cleanup(void)
     nspr_nss_init_done = 0;
     return EOK;
 }
+
+static int sss_nss_crypto_ctx_destructor(struct sss_nss_crypto_ctx *cctx)
+{
+    if (cctx->ectx) PK11_DestroyContext(cctx->ectx, PR_TRUE);
+    if (cctx->sparam) SECITEM_FreeItem(cctx->sparam, PR_TRUE);
+    if (cctx->slot) PK11_FreeSlot(cctx->slot);
+    if (cctx->keyobj) PK11_FreeSymKey(cctx->keyobj);
+
+    return EOK;
+}
+
+static int generate_random_key(TALLOC_CTX *mem_ctx,
+                               PK11SlotInfo *slot,
+                               struct crypto_mech_data *mech_props,
+                               SECItem **_key)
+{
+    SECStatus sret;
+    SECItem      *randkeydata;
+    SECItem      *key = NULL;
+    PK11SymKey   *randkey;
+    int ret;
+
+    randkey = PK11_KeyGen(slot, mech_props->cipher,
+                          NULL, mech_props->keylen, NULL);
+    if (randkey == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Failure to generate key (err %d)\n",
+                  PR_GetError());
+        ret = EIO;
+        goto done;
+    }
+
+    sret = PK11_ExtractKeyValue(randkey);
+    if (sret != SECSuccess) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Failure to extract key value (err %d)\n",
+                  PR_GetError());
+        ret = EIO;
+        goto done;
+    }
+
+    randkeydata = PK11_GetKeyData(randkey);
+    if (randkeydata == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Failure to get key data (err %d)\n",
+                  PR_GetError());
+        ret = EIO;
+        goto done;
+    }
+
+    /* randkeydata is valid until randkey is. Copy with talloc to
+     * get a nice memory hierarchy symmetrical in encrypt
+     * and decrypt case */
+    key = talloc_zero(mem_ctx, SECItem);
+    if (!key) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    key->data = talloc_memdup(key, randkeydata->data, randkeydata->len);
+    if (!key->data) {
+        ret = ENOMEM;
+        goto done;
+    }
+    key->len = randkeydata->len;
+
+    *_key = key;
+    ret = EOK;
+done:
+    if (ret != EOK) talloc_zfree(key);
+    PK11_FreeSymKey(randkey);
+    return ret;
+}
+
+int nss_ctx_init(TALLOC_CTX *mem_ctx,
+                 struct crypto_mech_data *mech_props,
+                 uint8_t *key, int keylen,
+                 uint8_t *iv, int ivlen,
+                 struct sss_nss_crypto_ctx **_cctx)
+{
+    struct sss_nss_crypto_ctx *cctx;
+    int ret;
+
+    cctx = talloc_zero(mem_ctx, struct sss_nss_crypto_ctx);
+    if (!cctx) {
+        return ENOMEM;
+    }
+    talloc_set_destructor(cctx, sss_nss_crypto_ctx_destructor);
+
+    cctx->slot = PK11_GetBestSlot(mech_props->cipher, NULL);
+    if (cctx->slot == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to find security device (err %d)\n",
+                  PR_GetError());
+        ret = EIO;
+        goto done;
+    }
+
+    if (keylen > 0) {
+        cctx->key = talloc(cctx, SECItem);
+        if (cctx->key == NULL) {
+            DEBUG(SSSDBG_CRIT_FAILURE,
+                  "Failed to allocate Key buffer\n");
+            ret = ENOMEM;
+            goto done;
+        }
+        if (key) {
+            MAKE_SECITEM(key, keylen, cctx->key);
+        } else {
+            ret = generate_random_key(cctx, cctx->slot,
+                                      mech_props, &cctx->key);
+            if (ret != EOK) {
+                DEBUG(SSSDBG_CRIT_FAILURE,
+                      "Could not generate encryption key\n");
+                goto done;
+            }
+        }
+
+    }
+
+    if (ivlen > 0) {
+        cctx->iv = talloc(cctx, SECItem);
+        if (cctx->iv == NULL) {
+            DEBUG(SSSDBG_CRIT_FAILURE, "Failed to allocate IV buffer\n");
+            ret = ENOMEM;
+            goto done;
+        }
+        if (iv) {
+            MAKE_SECITEM(iv, ivlen, cctx->iv);
+        } else {
+            ret = generate_random_key(cctx, cctx->slot,
+                                      mech_props, &cctx->iv);
+            if (ret != EOK) {
+                DEBUG(SSSDBG_CRIT_FAILURE,
+                      "Could not generate initialization vector\n");
+                goto done;
+            }
+        }
+    }
+
+    ret = EOK;
+    *_cctx = cctx;
+done:
+    if (ret) talloc_zfree(cctx);
+    return ret;
+}
+
+int nss_crypto_init(struct crypto_mech_data *mech_props,
+                    enum crypto_mech_op crypto_op,
+                    struct sss_nss_crypto_ctx *cctx)
+{
+    CK_ATTRIBUTE_TYPE op;
+    int ret;
+
+    switch (crypto_op) {
+    case op_encrypt:
+        op = CKA_ENCRYPT;
+        break;
+    case op_decrypt:
+        op = CKA_DECRYPT;
+        break;
+    case op_sign:
+        op = CKA_SIGN;
+        break;
+    default:
+        return EFAULT;
+    }
+
+    /* turn the raw key into a key object */
+    cctx->keyobj = PK11_ImportSymKey(cctx->slot, mech_props->cipher,
+                                     PK11_OriginUnwrap, op, cctx->key, NULL);
+    if (cctx->keyobj == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Failure to import key into NSS (err %d)\n",
+                  PR_GetError());
+        ret = EIO;
+        goto done;
+    }
+
+    if (crypto_op == op_encrypt || crypto_op == op_decrypt) {
+        /* turn the raw IV into a initialization vector object */
+        cctx->sparam = PK11_ParamFromIV(mech_props->cipher, cctx->iv);
+        if (cctx->sparam == NULL) {
+            DEBUG(SSSDBG_CRIT_FAILURE,
+                  "Failure to set up PKCS11 param (err %d)\n",
+                  PR_GetError());
+            ret = EIO;
+            goto done;
+        }
+    } else {
+        cctx->sparam = SECITEM_AllocItem(NULL, NULL, 0);
+        if (cctx->sparam == NULL) {
+            DEBUG(SSSDBG_CRIT_FAILURE, "Failure to allocate SECItem\n");
+            ret = EIO;
+            goto done;
+        }
+        MAKE_SECITEM(NULL, 0, cctx->sparam);
+    }
+
+    /* Create cipher context */
+    cctx->ectx = PK11_CreateContextBySymKey(mech_props->cipher, op,
+                                            cctx->keyobj, cctx->sparam);
+    if (cctx->ectx == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create cipher context (err %d)\n",
+                  PORT_GetError());
+        ret = EIO;
+        goto done;
+    }
+
+    ret = EOK;
+done:
+    return ret;
+}
diff --git a/src/util/crypto/nss/nss_util.h b/src/util/crypto/nss/nss_util.h
index 7387b9a7e0d602c81b2123a9c4bd263ed6501ab8..08ab58d87e64631a5b4cfa840bc78f038fda3977 100644
--- a/src/util/crypto/nss/nss_util.h
+++ b/src/util/crypto/nss/nss_util.h
@@ -22,6 +22,7 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+#include <nss.h>
 
 int nspr_nss_init(void);
 int nspr_nss_cleanup(void);
diff --git a/src/util/crypto/sss_crypto.c b/src/util/crypto/sss_crypto.c
new file mode 100644
index 0000000000000000000000000000000000000000..4c775f3d926ae32f3cb72b1329c0a025a0550ed5
--- /dev/null
+++ b/src/util/crypto/sss_crypto.c
@@ -0,0 +1,66 @@
+/*
+    Authors:
+        Simo Sorce <ssorce@redhat.com>
+
+    Copyright (C) 2016 Red Hat
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "config.h"
+#include "util/util.h"
+#include "util/crypto/sss_crypto.h"
+
+int generate_csprng_buffer(uint8_t *buf, size_t size)
+{
+    ssize_t rsize;
+    ssize_t pos;
+    int ret;
+    int fd;
+
+    fd = open("/dev/urandom", O_RDONLY);
+    if (fd == -1) return errno;
+
+    rsize = 0;
+    pos = 0;
+    while (rsize < size) {
+        rsize = read(fd, buf + pos, size - pos);
+        switch (rsize) {
+        case -1:
+            if (errno == EINTR) continue;
+            ret = EIO;
+            goto done;
+        case 0:
+            ret = EIO;
+            goto done;
+        default:
+            if (rsize + pos < size - pos) {
+                pos += rsize;
+                continue;
+            }
+            ret = EIO;
+            goto done;
+        }
+    }
+    if (rsize != size) {
+        ret = EFAULT;
+        goto done;
+    }
+
+    ret = EOK;
+
+done:
+    close(fd);
+    return ret;
+}
diff --git a/src/util/crypto/sss_crypto.h b/src/util/crypto/sss_crypto.h
index 5b40ecfc483e3696b2c549bf5ea25a969f12bb8c..8c7a883177d6a4be3309ce3374401626eb3fd04f 100644
--- a/src/util/crypto/sss_crypto.h
+++ b/src/util/crypto/sss_crypto.h
@@ -1,3 +1,24 @@
+/*
+    Copyright (C) 2009-2016 Red Hat
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _SSS_CRYPTO_H_
+#define _SSS_CRYPTO_H_
+
+int generate_csprng_buffer(uint8_t *buf, size_t size);
 
 int s3crypt_sha512(TALLOC_CTX *mmectx,
                    const char *key, const char *salt, char **_hash);
@@ -32,3 +53,19 @@ int sss_password_encrypt(TALLOC_CTX *mem_ctx, const char *password, int plen,
 
 int sss_password_decrypt(TALLOC_CTX *mem_ctx, char *b64encoded,
                          char **password);
+
+enum encmethod {
+    AES256CBC_HMAC_SHA256,
+    NUM_ENCMETHODS
+};
+
+int sss_encrypt(TALLOC_CTX *mem_ctx, enum encmethod enctype,
+                uint8_t *key, size_t keylen,
+                const uint8_t *plaintext, size_t plainlen,
+                uint8_t **ciphertext, size_t *cipherlen);
+int sss_decrypt(TALLOC_CTX *mem_ctx, enum encmethod enctype,
+                uint8_t *key, size_t keylen,
+                const uint8_t *ciphertext, size_t cipherlen,
+                uint8_t **plaintext, size_t *plainlen);
+
+#endif /* _SSS_CRYPTO_H_ */
-- 
2.5.5

